我们将各种数据存储为JSON列中的值/对。 对的名称在所有行中都不相同,并且取决于某些元数据。
有没有一种方法可以编写一条SQL语句来根据某些元数据检索其中一些值对?
类似于动态生成的
SELECT MyJson:FruitShape, MyJson:Fruitsize FROM MyTable WHERE ...
我了解我可以在存储过程中创建和执行动态SQL,但此SQL仅限于返回标量值。 我们需要一个记录集。
答案 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脚本,即使该脚本仅由两个查询组成也无法使用]