必须用sp_executesql而非exec拼动态where;参数为null表示“不限”,字段名须白名单校验不可拼入sql字符串,值参数必须显式声明类型并绑定传入。

优先用 sp_executesql 拼动态 WHERE,别用 EXEC(@sql);参数为 NULL 表示“不限”,字段名不能拼进 SQL 字符串里。
SQL Server 必须用 sp_executesql 而不是 EXEC
直接拼字符串再 EXEC(@sql) 会触发 SQL 注入、执行计划无法复用、类型隐式转换出错。而 sp_executesql 把 SQL 结构和参数值彻底分离——结构写死在字符串里,值全靠绑定传入。
关键点:
-
@sql字符串里只放骨架,比如' AND user_id = @user_id',不拼具体值 - 参数声明字符串必须带
N前缀且显式写类型:N'@user_id INT, @status VARCHAR(20)' -
EXEC sp_executesql @sql, @params, @user_id = @user_id, @status = @status—— 后面的参数名要和声明顺序严格一致 - 错误写法:
'WHERE name = ''' + @name + '''',既不安全又让缓存失效
MySQL 用 PREPARE + EXECUTE USING 替代 CONCAT 拼值
MySQL 不支持多参数绑定的系统过程,但 PREPARE + EXECUTE USING 能达到等效效果:占位符 ? 的数量和 USING 后变量顺序必须完全对齐。
实操要点:
- 每个条件判断是否启用:
IF in_user_id IS NOT NULL THEN SET @sql = CONCAT(@sql, ' AND user_id = ?'); - 变量列表要按
?出现顺序组装,最后EXECUTE stmt USING @user_id, @status; - 严禁
CONCAT('WHERE status = ''', in_status, '''')—— 单引号漏了、空值崩了、注入开了、类型乱了
PostgreSQL 字段名不能参数化,必须白名单校验
值可以绑定,字段名不行。任何把输入参数直接拼进 ORDER BY、GROUP BY 或 WHERE 左侧的操作,都是高危路径。
正确做法:
- 预设允许的字段名列表,比如
ARRAY['created_at', 'status', 'user_id'] - 用
IN或CASE显式比对:IF in_sort_field NOT IN ('created_at','status') THEN RAISE EXCEPTION 'invalid sort field'; END IF; - 错误示范:
EXECUTE 'SELECT * FROM t ORDER BY ' || in_sort_field;—— 字段名一失控就等于数据库裸奔
不用拼 SQL 的写法(仅限小表或低并发场景)
写成 WHERE (user_id = @user_id OR @user_id IS NULL) 看似简洁,但 SQL Server 查询优化器常误估行数,容易放弃索引走全表扫描。
适用边界很窄:
- 字段有大量
NULL值时,OR @param IS NULL可能被优化为索引查找 - 若参数传空字符串表示“不限”,就得写
OR @param = '',注意VARCHAR类型需考虑尾部空格 - 绝对不要用
CASE赋值形式:WHERE user_id = CASE WHEN @user_id IS NULL THEN user_id ELSE @user_id END—— 每行都强制计算,性能雪崩
字段上没索引、数据量不到万级、QPS 很低,这种写法才勉强可接受;否则就是给后续扩容埋雷。










