如何使用 Snowflake Javascript 存储过程或函数遍历表中的所有列?
Posted
技术标签:
【中文标题】如何使用 Snowflake Javascript 存储过程或函数遍历表中的所有列?【英文标题】:How to iterate over all columns in a table using Snowflake Javascript Stored Procedure or Function? 【发布时间】:2020-07-29 17:26:54 【问题描述】:我在 Snowflake 中有一个包含 100 多列的表,我试图获取每列中所有不同值的计数,并最终将每列的所有计数连接到一个表中。如果我只在一个专栏上做它会是这样的:
SELECT DISTINCT "AGE", count(*) AS "Frequency"
FROM
db.schema.tablename
WHERE
"SURVEYDATE" < "2019-07-29"
GROUP BY
AGE;
我知道这在 Python 中做起来有些微不足道(也许我应该只在 PySpark 中做,我愿意接受建议),但我认为这对我的团队来说既易于使用又可以更快地完成在 3 亿行中,我想使用 Snowflake javascript 程序语言来执行以下操作:
create or replace procedure column_counts(table)
returns array
language javascript
as
$$
var num_columns = //get number of columns
var columns = [list of columns]
var results_array = [];
for (i = 0; i < num_columns; i++)
var col_count = snowflake.createStatement( sqlText: 'SELECT DISTINCT columns[i], count(*) AS "Frequency" FROM
db.schema.tablename WHERE "SURVEYDATE" < "2019-07-29" GROUP BY columns[i]' ).execute(); //This returns a table of all distinct values in that column and their counts
results_array.push([columns[i], col_count]) //I then want an array like [column_name[0...i], distinct_value[0....n], frequency]
return results_array;
$$
;
CALL column_counts();
我对在 Snowflake 和整个 Snowflake 中使用这种程序语言还是很陌生,因此绝对愿意接受有关如何最好地做到这一点的建议,并以可重复的方式为每个月出现的新表提供建议。
【问题讨论】:
【参考方案1】:没有任何程序代码也是可能的。例如使用 JSON:
WITH cte AS ( -- here goes the table/query/view
SELECT TOP 100 OBJECT_CONSTRUCT(*) AS json_payload
FROM SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.ORDERS
)
SELECT f.KEY,
COUNT(DISTINCT f."VALUE") AS frequency,
LISTAGG(DISTINCT f."VALUE" ,',') AS distinct_values -- debug
FROM cte
, LATERAL FLATTEN (input => json_payload) f
-- WHERE f.KEY IN ('column_name1', 'column_name2', ...) -- only specific columns
GROUP BY f.KEY;
输出:
+-----------------+-----------+------------------------------------------------+
| KEY | FREQUENCY | DISTINCT_VALUES |
+-----------------+-----------+------------------------------------------------+
| O_ORDERPRIORITY | 5 | 2-HIGH,1-URGENT,5-LOW,4-NOT SPECIFIED,3-MEDIUM |
| O_ORDERSTATUS | 3 | P,O,F |
| O_SHIPPRIORITY | 1 | 0 |
| ... | ... | .... |
+-----------------+-----------+------------------------------------------------+
它是如何工作的:
使用OBJECT_CONSTRUCT(*)
为每一行生成 JSON
将 JSON 扁平化为键/值
按键分组并应用特定的聚合函数COUNT/COUNT(DISTINCT )/LISTAGG/MIN/MAX/...
提供每个列/值分布的版本:
WITH cte AS (
SELECT TOP 100 OBJECT_CONSTRUCT(*) AS json_payload
FROM SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.ORDERS
)
SELECT f.KEY, f."VALUE", COUNT(*) AS frequency
FROM cte
, LATERAL FLATTEN (input => json_payload) f
-- WHERE f.KEY IN ('column_name1', 'column_name2', ...) -- only specific columns
GROUP BY f.KEY, f."VALUE"
ORDER BY f.KEY, f."VALUE";
【讨论】:
太棒了,谢谢!我不知道如何使用 cte,我觉得我的眼睛已经打开了。我猜我可以使查询变得尽可能复杂,并且可以使用 IFF 语句等特定的特定列集,我不会有任何问题? 如果我想做 100 列中的 70 列,我该怎么做? @kwarner 您可以将 CTE 视为使用子查询的更好方式(它们也具有其他特性)。因此,您可以在 cte 中执行您喜欢的任何类型的转换,然后将其具体化为 JSON。至于限制列,您可以使用WHERE f.KEY IN ('col1', 'col2', ...)
或WHERE f.KEY LIKE 'colprefix%'
(如果它们有共同模式)
感谢您提供的所有有用信息。最后一个问题,如果我想采用 COUNT(*)/COUNT(DISTINCT(ID)) 这样的百分比,我将如何防止 ID 在这种情况下成为无效标识符?
@kwarner 这应该是一个新问题,包含样本数据和所需的结果集。无论如何,也许像: COUNT(*)/COUNT(DISTINCT CASE WHEN f.KEY = 'ID' THEN f."VALUE" END) 会做以上是关于如何使用 Snowflake Javascript 存储过程或函数遍历表中的所有列?的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript 内存不足错误:超出 UDF 线程内存限制-Snowflake
Snowflake 存储过程中的最大 JavaScript 字符串大小
在没有 JavaScript 的情况下将 Oracle PL/SQL 移植到 Snowflake