动态sql需兼顾灵活性与安全性:字段表名限白名单校验,数值强转类型,字符串必用sp_executesql参数化;禁用exec,调试先print,复杂逻辑宜静态+动态组合。

动态 SQL 是在运行时拼接并执行的 SQL 语句,常用于实现灵活查询、多条件筛选或表名/字段名动态化。但它容易出错、难调试、有注入风险,实际开发中需兼顾灵活性与安全性。
拼接前先验证参数合法性
动态 SQL 的第一道防线是控制输入来源。不能直接把用户传入的字段名、表名、排序方向拼进 SQL 字符串。
- 字段名、表名等应限定在白名单内(如用枚举或配置字典校验)
- 数值类参数用强类型转换(如 CAST(@page AS INT)),避免字符串隐式拼接
- 字符串值必须使用 sp_executesql 配合参数化,而非 + 拼接
优先用 sp_executesql 而非 EXEC
EXEC (@sql) 无法复用执行计划,也不支持参数化传值;sp_executesql 支持参数占位符,既防注入又提升性能。
✅ 正确示例:
DECLARE @sql NVARCHAR(MAX) = N'SELECT * FROM Users WHERE Status = @status AND CreatedTime > @since';EXEC sp_executesql @sql, N'@status TINYINT, @since DATETIME', @status = 1, @since = '2024-01-01';
调试时把 SQL 变量“打出来”再执行
别急着执行,先用 PRINT @sql 或 SELECT @sql 查看最终生成的语句。重点关注:
- 引号是否成对(特别是单引号嵌套)
- 字段/表别名有没有漏加括号或空格
- ORDER BY 后的变量是否被误当成字面量(如写成 ORDER BY @sortCol → 应改用 CASE 或白名单映射)
复杂逻辑建议拆成静态+动态组合
全动态难维护,可把稳定部分写成视图或 CTE,只让变化部分动态化。例如:
- 固定 JOIN 关系和基础过滤 → 写成视图 v_UserOrderSummary
- 仅动态控制 WHERE 条件或 TOP 数量 → 在外部拼接简单 SQL 查询该视图
- 既降低拼接复杂度,也利于执行计划缓存和权限管控










