根据另一个表中的数据在 FOR LOOP 中执行 Snowflake SQL 查询

not*_*ing 1 sql for-loop snowflake-cloud-data-platform

在 Snowflake 中,我尝试创建一个带有 for 循环的 SQL 脚本,该脚本根据 data_type 列将结果输出到新表中

我有一个名为 PROFILE_TABLE_LIST 的表,其中的列具有表名和列名以及数据类型,如下所示:

表名 COLUMN_NAME 数据类型
表格1 植物 文本
表格1 高度 漂浮
表2 颜色 文本
表2 文本

我目前正在尝试使用游标执行 for 循环,并对每一行执行查询,以根据列类型分析表,如下所示:

表名 COLUMN_NAME 数据类型 数数 最长长度 MAX_VALUE
表格1 植物 文本 10 82 无效的
表格1 高度 漂浮 10 无效的 58.6
表2 颜色 文本 20 56 无效的
表2 文本 20 23 无效的

最终,我想根据 data_type 运行不同的 select 语句,但在这个阶段,我只关注计数。这是我当前的循环。但是,由于表名作为字符串传递,因此 select 语句无法正确执行,如果我使用 TABLE(tablename) ,我会收到语法错误(我在下面注释掉了该行:

declare
    tablename string;
    column_name string;
    row_count integer;
    table_schema string;
    table_catalog string;
    name string;
    
    tmp_array ARRAY default ARRAY_CONSTRUCT();

    res resultset default (select * from PROFILE_TABLE_LIST);
    c1 cursor for res;
    rs_output RESULTSET;
begin

  for record in c1 do
    tablename := record.TABLENAME;
    column_name := record.column_name;
    table_schema := record.table_schema;
    table_catalog := record.table_catalog;
   
   
    
    tmp_array := array_append(:tmp_array, OBJECT_CONSTRUCT('tmp_tables', record.TABLENAME, 'COUNT', (SELECT COUNT(column_name) FROM tablename)));
    -- tmp_array := array_append(:tmp_array, OBJECT_CONSTRUCT('tmp_tables', record.TABLENAME, 'COUNT', (SELECT COUNT(column_name) FROM TABLE(tablename))));
 
     
    
  end for;

  rs_output := (select value:tmp_tables, value:COUNT from table(flatten(:tmp_array)));
  return table(rs_output);
end;
Run Code Online (Sandbox Code Playgroud)

Sim*_*rim 5

我会构建一个 SQL 块并在最后运行它。

它使用简单的 SELECT 作为模式来显示构建过程,您可以从中编写自己的动态 sql:

WITH table_list as (
    SELECT * FROM VALUES
    ('Table1', 'PLANTS', 'TEXT'),
    ('Table1', 'HEIGHT', 'FLOAT'),
    ('Table2', 'COLOR', 'TEXT'),
    ('Table2', 'SMELL', 'TEXT')
    v(tablename, column_name, data_type)
), to_rows as (
    SELECT
        tablename
        ,CASE data_type
            WHEN 'TEXT' THEN 'SELECT ''tablename'' as TABLENAME, ''column_name'' as COLUMN_NAME, ''data_type'' as DATA_TYPE, count(column_name) as count, MAX(LEN(column_name)) as max_length, null as max_value FROM tablename '
            WHEN 'FLOAT' THEN 'SELECT ''tablename'' as TABLENAME, ''column_name'' as COLUMN_NAME, ''data_type'' as DATA_TYPE, count(column_name) as count, null as max_length, MAX(column_name) as max_value FROM tablename '
        END as sql
        ,REPLACE(REPLACE(REPLACE(sql, 'data_type', data_type), 'column_name', column_name), 'tablename', tablename) as final_sql
    FROM table_list
)
SELECT
    listagg (final_sql, ' UNION ALL ') within group(order by tablename) as the_big_sql
FROM to_rows;
Run Code Online (Sandbox Code Playgroud)

这使:

THE_BIG_SQL
SELECT 'Table1' 作为 TABLENAME,'PLANTS' 作为 COLUMN_NAME,'TEXT' 作为 DATA_TYPE,count(PLANTS) 作为计数,MAX(LEN(PLANTS)) 作为 max_length,null 作为 max_value FROM Table1 UNION ALL SELECT 'Table1' 作为 TABLENAME, 'HEIGHT' 作为 COLUMN_NAME,'FLOAT' 作为 DATA_TYPE,count(HEIGHT) 作为计数,null 作为 max_length,MAX(HEIGHT) 作为 max_value FROM Table1 UNION ALL SELECT 'Table2' 作为 TABLENAME,'COLOR' 作为 COLUMN_NAME,'TEXT' as DATA_TYPE,count(COLOR) 作为计数,MAX(LEN(COLOR)) 作为 max_length,null 作为 max_value FROM Table2 UNION ALL SELECT 'Table2' 作为 TABLENAME,'SMELL' 作为 COLUMN_NAME,'TEXT' 作为 DATA_TYPE,count(SMELL) as count, MAX(LEN(SMELL)) 作为 max_length,null 作为 max_value FROM Table2

如果针对这些表运行:

create table table1(plants text, height float);
create table table2(color text, smell text);

insert into table1 values ('big plant', 10.1),('medium plant', 5.3),('tiny', 1.0);
insert into table2 values ('red', 'bold'), ('blue', 'weak');
Run Code Online (Sandbox Code Playgroud)

给出:

表名 COLUMN_NAME 数据类型 数数 最长长度 MAX_VALUE
表格1 植物 文本 3 12
表格1 高度 漂浮 3 10.1
表2 颜色 文本 2 4
表2 文本 2 4

但这是为您完整编写的动态答案:

首先用要完成的工作制作表格:

CREATE TABLE PROFILE_TABLE_LIST AS 
SELECT * FROM VALUES
    ('Table1', 'PLANTS', 'TEXT'),
    ('Table1', 'HEIGHT', 'FLOAT'),
    ('Table2', 'COLOR', 'TEXT'),
    ('Table2', 'SMELL', 'TEXT')
    v(tablename, column_name, data_type);
Run Code Online (Sandbox Code Playgroud)

并使用之前创建的“真实数据表”,我们可以使用:

declare
    sql string;
    final_sql string;
    c1 cursor for (select * from PROFILE_TABLE_LIST);
    res resultset;
begin
  final_sql := '';
  
  for record in c1 do
    if(record.data_type = 'TEXT') THEN
        sql := 'SELECT '''||record.tablename||''' as TABLENAME, '''||record.column_name||''' as COLUMN_NAME, '''||record.data_type||''' as DATA_TYPE, count('||record.column_name||') as count, MAX(LEN('||record.column_name||')) as max_length, null as max_value FROM '||record.tablename||' ';
    else
        sql := 'SELECT '''||record.tablename||''' as TABLENAME, '''||record.column_name||''' as COLUMN_NAME, ''data_type'' as DATA_TYPE, count('||record.column_name||') as count, null as max_length, MAX('||record.column_name||') as max_value FROM '||record.tablename||' ';
    end if;
    if(final_sql<>'')then 
        final_sql := final_sql || ' UNION ALL ';
    end if;
    final_sql := final_sql || sql;
        
  end for;

  res := (execute immediate :final_sql);
  return table(res);
end;
Run Code Online (Sandbox Code Playgroud)

给出:

表名 COLUMN_NAME 数据类型 数数 最长长度 MAX_VALUE
表格1 植物 文本 3 12
表格1 高度 数据类型 3 10.1
表2 颜色 文本 2 4
表2 文本 2 4