Snowflake存储过程调用SYSTEM$SEND_EMAIL时提示无效标识符错误
问题原因
在Snowflake SQL存储过程中,直接在CALL语句里引用变量(不管是写LINE还是:LINE)都会报错,因为SQL存储过程的语法规则限制:调用其他存储过程(包括系统存储过程)时,不能直接将变量作为参数传入CALL语句,必须通过动态SQL的方式传递变量。
解决方法
可以用两种方式修正代码,推荐第二种(更安全,避免单引号转义问题):
方法1:字符串拼接构造动态调用语句
将CALL语句改为用EXECUTE IMMEDIATE执行拼接后的SQL字符串,注意字符串中的单引号需要转义(写两个单引号):
CREATE OR REPLACE PROCEDURE testsproc() RETURNS VARCHAR LANGUAGE SQL AS $$ BEGIN SELECT * FROM non_existent_table; EXCEPTION WHEN OTHER THEN LET LINE := SQLCODE || ': ' || SQLERRM; INSERT INTO myexception VALUES (:LINE); -- 用EXECUTE IMMEDIATE拼接动态SQL EXECUTE IMMEDIATE 'CALL SYSTEM$SEND_EMAIL(''MYEMAIL'', ''abc@mail.com'', ''Errors!!'', ''' || LINE || ''')'; RETURN LINE; END; $$
方法2:用USING子句传递绑定变量(推荐)
通过EXECUTE IMMEDIATE的USING子句传递变量,无需处理单引号转义:
CREATE OR REPLACE PROCEDURE testsproc() RETURNS VARCHAR LANGUAGE SQL AS $$ BEGIN SELECT * FROM non_existent_table; EXCEPTION WHEN OTHER THEN LET LINE := SQLCODE || ': ' || SQLERRM; INSERT INTO myexception VALUES (:LINE); -- 用USING传递绑定变量 EXECUTE IMMEDIATE 'CALL SYSTEM$SEND_EMAIL(?, ?, ?, ?)' USING 'MYEMAIL', 'abc@mail.com', 'Errors!!', LINE; RETURN LINE; END; $$
说明
- 方法2中,
?是占位符,USING后面的参数会按顺序替换占位符,自动处理变量的类型和字符串转义,更可靠。 - 之前
INSERT语句能用:LINE是因为INSERT属于DML语句,SQL存储过程允许在DML中直接用绑定变量引用存储过程内的变量,但CALL调用存储过程的规则不同。
内容的提问来源于stack exchange,提问作者Aneesha
相关产品推荐
相关产品推荐

