是否可以生成动态SQL以返回雪花中具有不同列的行

时间:2019-12-10 15:14:52

标签: sql snowflake-data-warehouse

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

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

类似于动态生成的

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

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

4 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:3)

输入以下内容:

create or replace table t as
select parse_json($1) 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中执行此操作,例如通过过滤不同的字段列表。

使用result_scan()技术向davidgarrison致谢!

希望有帮助。

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

也许我在这里简化了事情,但是您不能……引用JSON列吗?
不需要存储过程或UDTF。

如果一个对象/行没有特定的属性,则其值为NULL,可以对其进行测试。

如果要以非平凡的方式转换对象和数组,则可以使用JavaScript,但是要获取简单的属性,只需在SQL中完成。

如果您想返回不同的列(不同的名称),那除了返回具有可变属性的VARIANT数据类型(例如,您的输入)之外是不可能的。

[编辑:davidgarrison / waldente的动态SQL / result_scan组合很好,但是可能很难从外部工具中以有限的方式执行SQL脚本,即使该脚本仅由两个查询组成也无法使用]