能做动态排序,但必须用CASE表达式+类型对齐+白名单控制:SQL Server需统一转VARCHAR并写ELSE;MySQL须PREPARE拼接且列名反引号包裹;PostgreSQL推荐多CASE并列+NULLS LAST。
能做,但不能直接拼字段名,必须用 CASE 表达式 + 类型对齐 + 白名单控制。 否则 SQL Server 会报 Conversion failed when converting the varchar value ...,MySQL 会静默错排,PostgreSQL 虽宽松但 NULL 位置不可控。
CASE 分支必须返回同一类型错误写法:ORDER BY CASE WHEN @sort = 'id' THEN id WHEN @sort = 'name' THEN name END——id 是 INT、name 是 VARCHAR,SQL Server 按数据类型优先级把整列转成 INT,结果不是报错就是字符串排序错乱(比如 '10' < '2')。
THEN 分支都显式转成同一种类型,推荐统一用 CONVERT(VARCHAR(100), xxx)
ELSE,且类型匹配,例如 ELSE '' 或 ELSE GETDATE(),不能留空让系统补 NULL
CONVERT(VARCHAR(23), col, 126) 格式化为 ISO8601 字符串,保证字典序等价于时间序COLLATE DATABASE_DEFAULT 避免排序规则冲突PREPARE 动态 SQL写 ORDER BY @sort_col 直接报 ERROR 1054: Unknown column '@sort_col'——MySQL 解析器在编译阶段就要求列名是字面量,运行时变量不被接受。
CONCAT() 拼接 SQL 字符串 + PREPARE + EXECUTE
ASC/DESC)都得拼进字符串,USING 只能传值,不能传结构CASE p_col WHEN 'name' THEN 'name' ELSE 'id' END 赋值给中间变量再拼,不能直接拼用户输入CONCAT('ORDER BY `', @safe_col, '` ', @safe_order),防关键字或空格字段出错CASE 并列 + NULLS LAST 显式控 NULL它比 SQL Server 宽松,允许不同类型的分支隐式转换,但默认 NULLS FIRST 常导致业务逻辑错乱(比如状态为 NULL 的记录总排最前)。
CASE 包所有字段,改用多个并列:ORDER BY CASE WHEN $1 = 'updated_at' THEN updated_at END DESC NULLS LAST, CASE WHEN $1 = 'name' THEN name END NULLS LAST
CASE 后紧跟 NULLS LAST,确保空值不干扰主排序逻辑$1 占位符,不是 @var,避免注入;存储过程用 IN 参数接收列名字符串CASE 几乎必然失效传 @sort_dir = 'DESC' 然后拼进 SQL 字符串?这是高危操作:触发执行计划缓存失效、无法参数化、还可能被注入。SQL Server 也不支持在 CASE 里动态切 ASC/DESC 关键字。
@sort_dir BIT(0=ASC,1=DESC),数值型参数可安全参与表达式CASE WHEN @sort_dir = 1 THEN -1 ELSE 1 END * price 再配 DESC
CASE WHEN @sort_dir = 1 THEN name END DESC, CASE WHEN @sort_dir = 0 THEN name END ASC
CASE 写法在 SQL Server 中会被合并为一个排序键,保持原生类型,不触发隐式转换最易被忽略的点是:动态排序几乎必然导致索引排序失效,除非你用 PostgreSQL 多 CASE 并列写法,或 MySQL 的 PREPARE 配合固定字段索引。别指望加个 OPTION (RECOMPILE) 就能救回性能——它只解决参数嗅探,不解决表达式无法走索引的本质问题。