使用结果

以内联方式返回结果

使用结果的最常见方法是将 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);
    }
  }
});
Copy

流式处理结果

您还可以将结果用作行流,方法是在调用 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);
    });
  }
});
Copy

批量处理结果

默认情况下, statement.streamRows() 方法生成一个包含结果中每一行的流。但是,如果只想使用结果的子集,或者要批量使用结果行,则可以使用 startend 实参调用 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);
    });
  }
})
Copy

数据类型转换

生成结果行时,驱动程序会自动将 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 列(包括 BIGINTNUMBER(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 ...
                        }
                      );
    
    Copy
  • 在连接配置信息中指定参数:

    var connection = snowflake.createConnection(
          {
          username: 'fakeusername',
          password: 'fakepassword',
          account: 'fakeaccountidentifier',
          jsTreatIntegerAsBigInt: true
          }
        );
    
    Copy

以字符串形式提取数据类型

调用 connection.execute() 时,可以使用 fetchAsString 选项,以字符串形式返回以下数据类型:BooleanNumberDateBufferJSON

例如,可以使用此选项返回以下内容:

  • 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
    }
  }
});
Copy

解析 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>
Copy

默认情况下,当 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: ''
  }
});
Copy

通过这些设置,驱动程序将解析 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
Copy

根据 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'})
    
    Copy
  • 语句级别

    connection.execute({
      sqlText: sql,
      rowMode: 'array',
      ...
      )}
    
    Copy

自定义结果集处理 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)
    })
    
    Copy
  • 使用 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)
    })
    
    Copy
  • 在同一声明中为两者配置自定义解析器:

    const snowflake = require('snowflake-sdk');
    snowflake.configure({
      jsonColumnVariantParser: rawColumnValue => JSON.parse(rawColumnValue),
      xmlColumnVariantParser: rawColumnValue => new (require("fast-xml-parser")).XMLParser().parse(rawColumnValue)
    })
    
    Copy
语言: 中文