英文:
Snowflake - execute immediate returns query text rather than the query result
问题
I understand you only want the translated parts. Here is the translated content:
我有一个表格,其中包含用于分析的SQL查询的列。我正在尝试使用"execute immediate"来返回这些SQL查询的结果。
如果我运行以下代码:
execute immediate 'select the_sql from analysis_queries';
它返回的与我只运行以下代码相同:
select the_sql from analysis_queries;
这是select count(*) as usr_ct from users;
。
我想要返回的是125
(实际的usr_ct)。
我尝试过以下代码:
set stmt = (select the_sql from analysis_queries);
execute immediate $stmt;
这确实返回了usr_ct,但对于更长的查询,它会引发错误:"Assignment to 'STMT' not done because value exceeds size limit for variables. Its size is 1,902; the limit is 256 (internal storage size in bytes)."
我对动态SQL/存储过程不熟悉,所以任何帮助都将非常感谢。谢谢!
英文:
I have a table that has a column that contains SQL queries used in analyses. I am trying to use execute immediate to return the results of those SQL queries.
Ex:
INSERT INTO ANALYSIS_QUERIES(DIR_NAME, FILE_NAME, THE_SQL) VALUES
(
'COUNT_CHECK'
,'USER_COUNT_CHECK.sql'
,'select
count(*) as usr_ct
from users;'
);
If I run
execute immediate 'select the_sql from analysis_queries'
it returns the same thing as if I had just run:
select the_sql from analysis_queries;
which is select count(*) as usr_ct from users;
What I want to return is 125
(the actual usr_ct).
I've tried
set stmt = (select the_sql from analysis_queries);
execute immediate $stmt;
Which does return the usr_ct, but there are longer queries where it throws an error Assignment to 'STMT' not done because value exceeds size limit for variables. Its size is 1,902; the limit is 256 (internal storage size in bytes).
I'm new to dynamic sql/stored procedures, so any help would be amazing.
Thank you,
答案1
得分: 2
警告!执行用户提供的任意查询是不安全的,因为恶意用户可能提供像 DROP DATABASE/DROP TABLE/ALTER USER/...
这样的 SQL 语句。
查询表格:
CREATE OR REPLACE TABLE ANALYSIS_QUERIES(DIR_NAME TEXT,
FILE_NAME TEXT,
THE_SQL TEXT,
RESULT INT) -- result column
AS
SELECT 'COUNT_CHECK','USER_COUNT_CHECK.sql',
'select count(*) as usr_ct from users;', NULL;
125 行的用户表格:
CREATE OR REPLACE TABLE users(col int) AS
SELECT seq4()
FROM TABLE(GENERATOR(ROWCOUNT=>125));
使用 Snowflake Scripting 块执行代码:
- 使用 CURSOR 和 FOR CURSOR LOOP 遍历 analysis_queries 表格
- 使用 EXECUTE IMMEDIATE 执行查询
- 使用 RESULT_SCAN(LAST_QUERY_ID()) 拦截输出并赋值给变量
代码示例:
DECLARE
cur CURSOR FOR SELECT *
FROM ANALYSIS_QUERIES
--WHERE ... -- 适用的话添加一些条件
;
sql_text TEXT;
dir_name TEXT;
file_name TEXT;
res INT;
BEGIN
FOR c IN cur DO
sql_text := c.THE_SQL;
dir_name := c.DIR_NAME;
file_name := c.FILE_NAME;
-- 执行查询
EXECUTE IMMEDIATE sql_text;
-- 拦截结果(假设是单行单列)并赋值给变量
res := (SELECT $1 FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())));
-- 将结果保存回表格
UPDATE ANALYSIS_QUERIES
SET result = :res
WHERE DIR_NAME = :dir_name
AND FILE_NAME = :file_name;
END FOR;
RETURN 'Success';
END;
输出:
SELECT * FROM ANALYSIS_QUERIES;
|DIR_NAME |FILE_NAME |THE_SQL |RESULT|
|-------------|---------------------|---------------------------------------------|------|
|COUNT_CHECK |USER_COUNT_CHECK.sql |select count(*) as usr_ct from users; |125 |
方法 2:
> I've tried
>
> set stmt = (select the_sql from analysis_queries);
> execute immediate $stmt;
使用 Snowflake Scripting 块执行代码:
BEGIN
LET THE_SQL TEXT := (SELECT THE_SQL
FROM ANALYSIS_QUERIES
WHERE FILE_NAME = 'USER_COUNT_CHECK.sql');
LET RES RESULTSET := (EXECUTE IMMEDIATE :THE_SQL);
RETURN TABLE(RES);
END;
输出:
|USR_CT|
|------|
|125 |
相关:在 SnowSQL 和经典控制台中使用 Snowflake 脚本
英文:
Warning!
Running an arbitrary query provided by user is NOT secure, for instance malicious user may provide sql_text like DROP DATABASE/DROP TABLE/ALTER USER/...
.
Query table:
CREATE OR REPLACE TABLE ANALYSIS_QUERIES(DIR_NAME TEXT,
FILE_NAME TEXT,
THE_SQL TEXT,
RESULT INT) -- result column
AS
SELECT 'COUNT_CHECK','USER_COUNT_CHECK.sql',
'select count(*) as usr_ct from users;', NULL;
-- 125 rows users table
CREATE OR REPLACE TABLE users(col int) AS
SELECT seq4()
FROM TABLE(GENERATOR(ROWCOUNT=>125));
SELECT * FROM ANALYSIS_QUERIES;
DIR_NAME | FILE_NAME | THE_SQL | RESULT |
---|---|---|---|
COUNT_CHECK | USER_COUNT_CHECK.sql | select count(*) as usr_ct from users; | null |
Executing code using Snowflake Scripting block:
- CURSOR and FOR CURSOR LOOP to iterate over analysis_queries table
- EXECUTE IMMEDIATE to run the query
- RESULT_SCAN(LAST_QUERY_ID()) - intercepting the output and assigning to variable
Code:
DECLARE
cur CURSOR FOR SELECT *
FROM ANALYSIS_QUERIES
--WHERE ... -- some condition if needed
;
sql_text TEXT;
dir_name TEXT;
file_name TEXT;
res INT;
BEGIN
FOR c IN cur DO
sql_text := c.THE_SQL;
dir_name := c.DIR_NAME;
file_name := c.FILE_NAME;
-- run the query
EXECUTE IMMEDIATE sql_text;
-- intercept result(assumption single row/single column) to variable
res := (SELECT $1 FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())));
-- save result back into table
UPDATE ANALYSIS_QUERIES
SET result = :res
WHERE DIR_NAME = :dir_name
AND FILE_NAME = :file_name;
END FOR;
RETURN 'Success';
END;
Output:
SELECT * FROM ANALYSIS_QUERIES;
DIR_NAME | FILE_NAME | THE_SQL | RESULT |
---|---|---|---|
COUNT_CHECK | USER_COUNT_CHECK.sql | select count(*) as usr_ct from users; | 125 |
Approach 2:
> I've tried
>
> set stmt = (select the_sql from analysis_queries);
> execute immediate $stmt;
Using Snowflake Scripting block:
BEGIN
LET THE_SQL TEXT := (SELECT THE_SQL
FROM ANALYSIS_QUERIES
WHERE FILE_NAME = 'USER_COUNT_CHECK.sql');
LET RES RESULTSET := (EXECUTE IMMEDIATE :THE_SQL);
RETURN TABLE(RES);
END;
Output:
USR_CT |
---|
125 |
Related: Using Snowflake Scripting in SnowSQL and the Classic Console
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论