TOP WITH TIES 是在排序后取前 N 行并包含所有与第 N 行排序值相同的行,本质区别在于:普通 TOP 严格返回指定行数,而 WITH TIES 可能返回更多行;它必须配合 ORDER BY 使用,依据整个排序键判断并列,而非仅末位字段。

TOP WITH TIES 是什么,它和普通 TOP 有什么本质区别
TOP WITH TIES 不是简单地取前 N 行,而是取“排序后并列第 N 名及所有与之同分的行”。关键前提是必须配合 ORDER BY 使用,否则语法报错。它依赖的是排序结果中的重复值边界——比如你写 TOP 3 WITH TIES,SQL Server 会先按 ORDER BY 排序,取前 3 行,再检查第 3 行的排序字段值是否在后续行中重复出现;如果有,就把所有相同值的行都拉进来。
常见错误现象:Msg 10757, Level 15, State 1: WITH TIES can only be specified when ORDER BY is also specified. —— 忘加 ORDER BY 就会这样。
怎么写一个能体现并列效果的典型查询
假设有一张 sales 表,含 product、amount 字段,你想取销售额最高的前 2 个产品,但允许并列:
SELECT TOP 2 WITH TIES product, amount FROM sales ORDER BY amount DESC;
如果数据是:('A', 100)、('B', 90)、('C', 90)、('D', 85),结果会返回 A、B、C 三行(因为第 2 名是 90,而 C 也等于 90)。
- 不能用
TOP 2替代——它只会硬截断为 2 行,丢掉 C -
ORDER BY字段必须是确定性排序依据;如果用ORDER BY NEWID()这类非确定性表达式,WITH TIES行为不可预测 - 多个排序字段时,
WITH TIES只看最末尾字段是否“并列”?错——它看的是整个ORDER BY子句构成的**排序键组合**是否重复。例如ORDER BY category, amount DESC,则只有 category 和 amount 都相同时才算 ties
为什么有时结果行数远超预期,甚至全表返回
这是最容易踩的坑:当 ORDER BY 字段存在大量重复值(尤其是全表该字段值都一样),TOP n WITH TIES 就可能把整张表都拉出来。比如对一张用户表按 status(全为 'active')排序取 TOP 1 WITH TIES,结果就是全部行。
性能影响明显:SQL Server 仍需扫描/排序全部数据才能确认“哪些行和第 n 行有相同排序键”,无法像普通 TOP n 那样早期终止。
- 务必检查
ORDER BY字段的基数(distinct 值数量) - 若业务上需要稳定限制返回行数,不要依赖
WITH TIES做分页或限流 - 执行计划里注意是否有
Top N Sort→ 实际却是Sort全排序,说明优化器没走捷径
替代方案:ROW_NUMBER() vs RANK() vs DENSE_RANK()
当 TOP WITH TIES 不够灵活(比如要跳过前 2 名再取并列第 3 名),就得换窗口函数。核心区别在于排名逻辑:
-
ROW_NUMBER():严格不并列,1,2,3,4… -
RANK():并列且跳号,1,1,3,3,5…(对应TOP WITH TIES的语义) -
DENSE_RANK():并列但不跳号,1,1,2,2,3…
例如取“销售额并列第 2 名的所有产品”,用 RANK() 更直接:
SELECT product, amount
FROM (
SELECT product, amount,
RANK() OVER (ORDER BY amount DESC) AS rnk
FROM sales
) t
WHERE rnk = 2;
这个写法比嵌套 TOP WITH TIES 更可控,也更容易加过滤、分组或 JOIN。
真正难处理的是排序字段本身存在 NULL——SQL Server 默认把 NULL 排在最前(ASC)或最后(DESC),而 WITH TIES 会把所有 NULL 当作相同值合并。这点常被忽略,尤其在统计类查询中导致意外多出一堆 NULL 行。

















