DATEADD函数存储过程参数报错:如何传递日期/时间组件参数
问题描述
已知DATEADD函数的两种写法均有效:
SELECT DATEADD(hour, -1, CURRENT_TIMESTAMP), DATEADD('hour', -1, CURRENT_TIMESTAMP)
我希望在存储过程中传递类似'hour'这类日期组件参数,于是定义了带varchar类型参数的存储过程:
CREATE OR REPLACE PROCEDURE "EXECUTE_INSERT_TEST"(hour_or_date varchar, Load_day_number number, load_day_from timestamp) RETURNS NUMBER(38,0) LANGUAGE SQL EXECUTE AS OWNER AS 'begin INSERT INTO TABLE_1 (FILE_NAME, LOAD_DATE) SELECT FILE_NAME, LOAD_DATE FROM TABLE_2 where 1 = 1 and LOAD_DATE >= DATEADD(hour_or_date, -1, CURRENT_TIMESTAMP) ; RETURN 1; end';
调用存储过程时:
CALL "EXECUTE_INSERT_TEST"('hour', -1, CURRENT_TIMESTAMP)
出现如下错误:
SQL Error [2151] [22023]: Uncaught exception of type 'STATEMENT_ERROR' on line 3 at position 0 : SQL compilation error: ['HOUR_OR_DATE'] is not a valid date/time component for function DATEADD.
请问该如何正确传递hour或date这类日期/时间组件参数?
解决方案
Snowflake的DATEADD函数第一个参数是日期/时间组件的字面量,编译时会直接解析参数名称而非变量值,所以直接传变量名会被当成无效组件报错。可以通过以下两种方式解决:
方法1:条件分支处理
针对有限的组件类型,用CASE分支调用对应写法的DATEADD:
CREATE OR REPLACE PROCEDURE "EXECUTE_INSERT_TEST"(hour_or_date varchar, Load_day_number number, load_day_from timestamp) RETURNS NUMBER(38,0) LANGUAGE SQL EXECUTE AS OWNER AS 'begin INSERT INTO TABLE_1 (FILE_NAME, LOAD_DATE) SELECT FILE_NAME, LOAD_DATE FROM TABLE_2 where 1 = 1 and LOAD_DATE >= CASE hour_or_date WHEN ''hour'' THEN DATEADD(hour, -1, CURRENT_TIMESTAMP) WHEN ''day'' THEN DATEADD(day, -1, CURRENT_TIMESTAMP) WHEN ''month'' THEN DATEADD(month, -1, CURRENT_TIMESTAMP) -- 可按需扩展其他合法组件 ELSE CURRENT_TIMESTAMP -- 非法参数的默认处理逻辑 END; RETURN 1; end';
这种方式编译时就能确认DATEADD的参数合法性,适合组件类型固定的场景。
方法2:动态SQL拼接
如果需要支持更多组件类型,可通过动态SQL将参数值拼接到语句中执行:
CREATE OR REPLACE PROCEDURE "EXECUTE_INSERT_TEST"(hour_or_date varchar, Load_day_number number, load_day_from timestamp) RETURNS NUMBER(38,0) LANGUAGE SQL EXECUTE AS OWNER AS 'begin -- 先校验参数合法性,避免非法组件或SQL注入风险 IF hour_or_date NOT IN (''hour'', ''day'', ''month'', ''minute'', ''second'') THEN RETURN -1; -- 返回错误标识 END IF; -- 拼接动态SQL语句 LET sql_stmt VARCHAR := '' INSERT INTO TABLE_1 (FILE_NAME, LOAD_DATE) SELECT FILE_NAME, LOAD_DATE FROM TABLE_2 where 1 = 1 and LOAD_DATE >= DATEADD(''||hour_or_date||'', -1, CURRENT_TIMESTAMP) ''; -- 执行动态SQL EXECUTE IMMEDIATE sql_stmt; RETURN 1; end';
注意:必须添加参数合法性校验,防止非法输入导致语法错误或安全问题。
内容的提问来源于stack exchange,提问作者x89
相关产品推荐
相关产品推荐

