如何在存储过程的IN语句中使用传入的字符串参数
问题根因
你当前写法失效的核心原因是:MySQL 不会将存储过程中 IN (v_act_date) 里的字符串变量自动解析为多值集合,字符串内的逗号只会被识别为普通字符,str_to_date 函数也不会被执行,最终相当于把整个长字符串作为单个值和 act_date 字段匹配,自然匹配不到任何数据,不会触发更新。
解决方案
方案1:使用动态预处理SQL(适配你现有传参逻辑)
直接在存储过程内拼接SQL语句后执行,兼容你当前脚本侧的传参格式,修改后的存储过程代码如下:
CREATE PROCEDURE `test`( IN v_act_date varchar(1024) ) BEGIN -- 拼接完整的更新SQL SET @update_sql = CONCAT('update db.my_table set upd=0 where act_date in (', v_act_date, ')'); -- 预处理并执行SQL PREPARE stmt FROM @update_sql; EXECUTE stmt; -- 释放预处理资源 DEALLOCATE PREPARE stmt; END
脚本侧的调用逻辑不需要修改,原有转义单引号的逻辑保留即可。
注意:该方案存在SQL注入风险,如果
v_act_date参数的来源不可信,需要提前做严格的内容校验。
方案2:使用FIND_IN_SET函数(无动态SQL,更安全)
如果不想用动态SQL,可以调整传参格式,只传逗号分隔的日期字符串,不需要拼接str_to_date函数,实现逻辑如下:
- 脚本侧传参调整:
v_act_date = "01-10-2021,02-10-2021,31-10-2021" conn.execute("call test('" & v_act_date & "');")
- 存储过程修改为:
CREATE PROCEDURE `test`( IN v_act_date varchar(1024) ) BEGIN UPDATE db.my_table SET upd=0 WHERE FIND_IN_SET(DATE_FORMAT(act_date, '%d-%m-%Y'), v_act_date) > 0; END
方案对比
- 方案1适配现有传参逻辑,不需要调整脚本侧代码,适合参数来源可控的内部系统场景
- 方案2避免了动态SQL的注入风险,性能更稳定,适合参数来源不可信的生产环境
内容的提问来源于stack exchange,提问作者dannielsen
相关产品推荐
相关产品推荐

