使用结果¶
以内联方式返回结果¶
使用结果的最常见方法是将 complete
回调传递给 connection.execute()
。当语句执行完毕并且结果可供使用时,将调用 complete
回调,并以内联方式返回结果行:
connection.execute({ sqlText: 'SELECT * FROM sometable', complete: function(err, stmt, rows) { if (err) { console.error('Failed to execute statement due to the following error: ' + err.message); } else { console.log('Number of rows produced: ' + rows.length); } } });
流式处理结果¶
您还可以将结果用作行流,方法是在调用 statement.streamRows()
方法时将 connection.execute
中的 streamResult
连接参数设置为 true
。通过启用此参数,该方法可返回 Node.js Readable
流,您可以使用该流在收到行时使用这些行。
重要
对于可能超出 Node 默认内存的任何结果集,Snowflake 强烈建议您在流式处理结果时将 streamResult
设置为 true
。使用默认值 (false
),连接器会在流式处理结果之前将所有行存储在数组中。对于较小的结果集,此因素通常不是问题。但是,对于较大的结果集,将所有结果存储在内存中可能会导致 OOM 错误。
Snowflake Node.js 驱动程序的最新版本(1.6.23 及更高版本)实现了背压功能,以确保在使用结果时,将数据推送到流的速度不会快于从流中读取数据的速度。
例如,以下代码片段通过 Readable
事件使用结果:
var connection = snowflake.createConnection({ account: process.env.SFACCOUNT, username: process.env.SFUSER, // ... streamResult: true }); // [..rest of the code..] connection.execute({ sqlText: "select L_COMMENT from SNOWFLAKE_SAMPLE_DATA.TPCH_SF100.LINEITEM limit 100000;", streamResult: true, complete: function (err, stmt) { var stream = stmt.streamRows(); // Read data from the stream when it is available stream.on('readable', function (row) { while ((row = this.read()) !== null) { console.log(row); } }).on('end', function () { console.log('done'); }).on('error', function (err) { console.log(err); }); } });
批量处理结果¶
默认情况下, statement.streamRows()
方法生成一个包含结果中每一行的流。但是,如果只想使用结果的子集,或者要批量使用结果行,则可以使用 start
和 end
实参调用 streamRows()
。指定这些附加选项时,仅流式处理请求范围内的行:
connection.execute({ sqlText: 'SELECT * FROM sometable', streamResult: true, // prevent rows from being returned inline in the complete callback complete: function(err, stmt, rows) { // no rows returned inline because streamResult was set to true console.log('rows: ' + rows); // 'rows: undefined' // only consume at most the last 5 rows in the result rows = []; stmt.streamRows({ start: Math.max(0, stmt.getNumRows() - 5), end: stmt.getNumRows() - 1, }) .on('error', function(err) { console.error('Unable to consume requested rows'); }) .on('data', function(row) { rows.push(row); }) .on('end', function() { console.log('Number of rows consumed: ' + rows.length); }); } })
数据类型转换¶
生成结果行时,驱动程序会自动将 SQL 数据类型映射到其对应的 JavaScript 等效项。例如, TIMESTAMP 和 DATE 类型的值以 JavaScript Date 对象的形式返回。
有关 JavaScript 到 SQL 数据类型的完整映射,请参阅下表:
SQL 数据类型
JavaScript 数据类型
备注
VARCHAR、CHAR、CHARACTER、STRING、TEXT
字符串
INT、INTEGER、BIGINT、SMALLINT
数字
这是默认映射。使用会话参数 JS_TREAT_INTEGER_AS_BIGINT 映射到 JavaScript Bigint。
NUMBER(精度,小数位数)、DECIMAL(精度,小数位数)、NUMERIC(精度,小数位数),其中
scale
= 0数字
这是默认映射。使用会话参数 JS_TREAT_INTEGER_AS_BIGINT 映射到 JavaScript Bigint。
NUMBER(精度,小数位数)、DECIMAL(精度,小数位数)、NUMERIC(精度,小数位数),其中
scale
> 0数字
FLOAT、FLOAT4、FLOAT8、DOUBLE、DOUBLE、PRECISION、REAL
数字
TIMESTAMP、TIMESTAMP_LTZ、TIMESTAMP_NTZ、TIMESTAMP_TZ
日期
返回的 TIMESTAMP_NTZ 值采用 UTC。
DATE
日期
TIME
字符串
SQL 中的 TIME 数据类型在 JavaScript 中没有等效项,因此它映射到 JavaScript 字符串。
BOOLEAN
布尔
VARIANT、ARRAY、OBJECT
JSON
以 Bigint 形式提取整数数据类型¶
默认情况下,Snowflake INTEGER 列(包括 BIGINT
、NUMBER(p, 0)
等)会转换为 JavaScript 的 Number
数据类型。但是,最大的合法 Snowflake 整数值大于最大的合法 JavaScript 数字值。要将 Snowflake INTEGER
列转换为 JavaScript Bigint
(可以存储比 JavaScript Number
更大的值),请设置会话参数 JS_TREAT_INTEGER_AS_BIGINT
。
您可以使用以下方法设置这些参数值:
使用 ALTER SESSION 语句,如下所示:
connection.execute( { sqlText: 'ALTER SESSION SET JS_TREAT_INTEGER_AS_BIGINT = TRUE', complete: function ... } );
在连接配置信息中指定参数:
var connection = snowflake.createConnection( { username: 'fakeusername', password: 'fakepassword', account: 'fakeaccountidentifier', jsTreatIntegerAsBigInt: true } );
以字符串形式提取数据类型¶
调用 connection.execute()
时,可以使用 fetchAsString
选项,以字符串形式返回以下数据类型:Boolean
、Number
、Date
、Buffer
和 JSON
。
例如,可以使用此选项返回以下内容:
DATE 和 TIMESTAMP 类型(或其变体)值的格式化版本。
SQL 数字类型的字符串版本,无法在不损失精度的情况下转换为 JavaScript 数字。
以下示例使用 fetchAsString
将高精度 Number
值转换为字符串:
connection.execute({
sqlText: 'SELECT 1.123456789123456789123456789 as "c1"',
fetchAsString: ['Number'],
complete: function(err, stmt, rows) {
if (err) {
console.error('Failed to execute statement due to the following error: ' + err.message);
} else {
console.log('c1: ' + rows[0].c1); // c1: 1.123456789123456789123456789
}
}
});
解析 XML 数据¶
从驱动程序版本 1.7.0 开始,可以使用以下 fast-xml-parser
库配置选项,在查询包含 XML 内容的列时,自定义驱动程序处理 XML 文档属性的方式。要详细了解这些支持的选项以及它们如何影响 XML 数据解析,请参阅 xmlParserConfig 选项。
默认情况下,Node.js 驱动程序在从查询返回 XML 数据时忽略 XML 元素属性。例如,在以下 XML 内容中, <piece>
元素包含 id
属性:
<exhibit name="Art Show">
<piece id="000001">
<name>Mona Lisa</name>
<artist>Leonardo da Vinci</artist>
<year>1503</year>
</piece>
<piece id="000002">
<name>The Starry Night</name>
<artist>Vincent van Gogh</artist>
<year>1889</year>
</piece>
</exhibit>
默认情况下,当 Node.js 驱动程序返回结果集时,它会忽略 id
属性并返回以下输出。请注意,不包括属性名称和值。
{
exhibit: {
piece: [
{
"name": "Mona Lisa",
"artist": "Leonardo da Vinci",
"year": "1503",
},
{
"name": "The Starry Night",
"artist": "Vincent van Gogh",
"year": "1889",
}
]
}
}
要设置 fast-xml-parser
选项,请创建一个与下方示例类似的 xmlParserConfig
元素:
const snowflake = require('snowflake-sdk'); snowflake.configure({ xmlParserConfig: { /* Parameters that you can override * ignoreAttributes - default true, * attributeNamePrefix - default '@_', * attributesGroupName - default unset, * alwaysCreateTextNode - default false */ ignoreAttributes: false, attributesGroupName: '@', attributeNamePrefix: '' } });
通过这些设置,驱动程序将解析 XML 数据并生成以下内容:
{
exhibit: {
piece: [
{
"name": "Mona Lisa",
"artist": "Leonardo da Vinci",
"year": "1503",
'@': { id: '000001' }
},
{
"name": "The Starry Night",
"artist": "Vincent van Gogh",
"year": "1889",
'@': { id: '000002' }
}
],
'@': { name: 'Art Show' }
}
返回包含重复列名的结果集¶
在版本 1.8.0 中,Snowflake Node.js 驱动程序推出了一个新的 rowMode 配置选项,该选项允许您指定希望驱动程序如何返回包含重复列名的结果集。
在版本 1.8.0 之前的版本中,Snowflake Node.js 驱动程序始终通过 SELECT 命令以 JavaScript 对象的形式返回结果集。如果结果集包含重复列名和值,可能省略某些元素,具体取决于 JavaScript 对象处理重复名称的方式。
rowMode
选项允许您指定返回结果集数据的方式,以避免潜在的信息丢失,包括以下方式:
array
object
(默认)object_with_renamed_duplicated_columns
为了说明这一点,假设您提交了以下查询:
select *
from (select 'a' as key, 1 as foo, 3 as name) as table1
join (select 'a' as key, 2 as foo, 3 as name2) as table2 on table1.key = table2.key
join (select 'a' as key, 3 as foo) as table3 on table1.key = table3.key
根据 rowMode
的值,驱动程序返回结果集,如下所示:
object
(或未设置){KEY: 'a', FOO: 3, NAME: 3, NAME2: 3};
array
['a', 1, 3, 'a', 2, 3, 'a', 3];
object_with_renamed_duplicated_columns
{KEY: 'a', FOO: 1, NAME: 3, KEY_2: 'a', FOO_2: 2, NAME2: 3, KEY_3: 'a', FOO_3: 3};
您可以在连接或语句配置级别设置 rowMode
参数,如下所示。如果在这两个级别都进行了设置,则语句级别值优先。
配置级别
snowflake.createConnection({ account: account, username: username, ... rowMode: 'array'})
语句级别
connection.execute({ sqlText: sql, rowMode: 'array', ... )}
自定义结果集处理 JSON 和 XML 数据的方式¶
Snowflake Node.js 驱动程序提供以下默认解析器来处理结果集中的 JSON 和 XML 数据:
JSON:从新
Function
对象中返回结果。XML:
fast-xml-parser
。默认
fast-xml-parser
模块支持部分功能,如 解析 XML 数据 中所述。
如果希望使用自定义解析器,可以根据以下示例来配置它们:
使用 eval JSON 解析器,在版本 1.6.21 之前的版本中,驱动程序使用的是该解析器:
const snowflake = require('snowflake-sdk'); snowflake.configure({ jsonColumnVariantParser: rawColumnValue => JSON.parse(rawColumnValue) })
使用
fast-xml-parser
解析器,该解析器能够 自定义其所有选项 (https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/docs/v4/2.XMLparseOptions.md):const snowflake = require('snowflake-sdk'); snowflake.configure({ xmlColumnVariantParser: rawColumnValue => new (require("fast-xml-parser")).XMLParser().parse(rawColumnValue) })
在同一声明中为两者配置自定义解析器:
const snowflake = require('snowflake-sdk'); snowflake.configure({ jsonColumnVariantParser: rawColumnValue => JSON.parse(rawColumnValue), xmlColumnVariantParser: rawColumnValue => new (require("fast-xml-parser")).XMLParser().parse(rawColumnValue) })