是否可以在雪花中生成动态 sql 到 return 具有各种列的行

Is it possible to generate dynamic sql to return rows with various columns in snowflake

我们将各种数据存储为 value/pairs 在 JSON 列中。 所有行的对名称都不相同,并且取决于某些元数据。

有没有一种方法可以编写 SQL 语句来根据某些元数据检索其中一些值对?

类似于动态生成的东西

SELECT MyJson:FruitShape, MyJson:Fruitsize FROM MyTable WHERE ...

我知道我可以在存储过程中创建和执行动态 SQL,但是这个 SQL 仅限于返回标量值... 我们需要一个记录集。

我会为此利用 javascript UDTF。它提供与存储过程相同的功能,但具有 table 输出。

https://docs.snowflake.net/manuals/sql-reference/udf-js-table-functions.html

如果您已经准备好动态 sql,除了标量值之外,还有其他方法可以从存储过程中获取结果集。

您可以浏览 SnowFlake 文档中的一些选项和示例:

也许我在这里过度简化了事情,但你不能...参考 JSON 列吗?
不需要存储过程或 UDTF。

如果一个 object/row 没有特定的属性,它的值将为 NULL 并且可以被测试。

如果你想以非平凡的方式转换对象和数组,JavaScript 是可行的方法,但要获得简单的属性,只需在 SQL 中进行即可。

如果您想 return 不同的列(不同的名称),那是不可能的,除非 return 具有不同属性的 VARIANT 数据类型(即像您的输入)。

[编辑:davidgarrison/waldente 的动态 SQL/result_scan 组合很好,但可能仍然难以通过执行 SQL 脚本的有限方式使用外部工具,即使该脚本仅包含两个查询]

鉴于此输入:

create or replace table t as
select parse_json() my_json
from values
('{ "FruitShape":"Round", "FruitSize":55 } '),
('{ "FruitShape":"Square"  } '),
('{ "FruitShape":"Oblong", "FruitSize":22, "FruitColor":"Chartreuse" } ')
;

此查询将生成动态 SQL:

select 'select ' 
  || (select listagg(distinct 'my_json:'||key::text, ',') from t, lateral flatten(input=>t.my_json, mode=>'OBJECT')) 
  || ' from t;';

生成了 SQL 并且输出:

select my_json:FruitShape, my_json:FruitSize, my_json:FruitColor from t;

MY_JSON:FRUITSHAPE | MY_JSON:FRUITSIZE | MY_JSON:FRUITCOLOR
-------------------+-------------------+-------------------
"Round"            | 55                | NULL              
"Square"           | NULL              | NULL              
"Oblong"           | 22                | "Chartreuse"      

此存储过程将执行动态 SQL 而无需剪切和粘贴:

create or replace procedure p()
returns string
language javascript
strict
execute as caller
as
$$
  const statement1 =  `
    select 'select ' 
      || (select listagg(distinct 'my_json:'||key::text, ', ') from t, lateral flatten(input=>t.my_json, mode=>'OBJECT')) 
      || ' from t'
  `
  const rs1 = snowflake.execute ({sqlText: statement1})
  rs1.next()
  const statement2 = rs1.getColumnValue(1)
  const rs2 = snowflake.execute ({sqlText: statement2})
  return 'SUCCESS'
$$
;

然后就可以调用存储过程并收集结果了:

call p();
select * from table(result_scan(-2))

您提到根据某些元数据限制输出。您可以在动态 SQL 中执行此操作,例如通过过滤不同的字段列表。

感谢 davidgarrison 的 result_scan() 技巧!

希望对您有所帮助。