如何编写有效SQL查询:按DocNum降序取前25个去重customer?
如何编写符合需求的SQL查询
你的需求是按DocNum字段降序排序,获取前25个不重复的customer字段值,但当前给出的查询存在逻辑问题,无法正确实现需求,下面具体分析并给出解决方案:
原查询的问题
原查询语句:
SELECT DISTINCT TOP 25 customer FROM tt WHERE DocNum LIKE '%_%' AND UPPER(U_NAME) NOT LIKE '%E G%' ORDER BY DocNum DESC
这里的核心矛盾:
DISTINCT会先对customer去重,但ORDER BY DocNum DESC依赖的是未去重前的记录字段,多数SQL数据库(如SQL Server)会直接报错,因为无法确定每个去重后的customer对应哪个DocNum来排序;- 即使部分数据库允许执行,结果也不符合预期——同一个
customer可能对应多个DocNum,排序逻辑混乱,无法保证取到的是拥有最大DocNum的前25个客户。
正确的实现方案
根据需求核心,分两种常见场景给出写法:
场景1:取拥有最大DocNum的前25个不同客户
这是最常见的需求逻辑:先找出每个客户最新(最大)的DocNum,再按该值降序排序,取前25个客户。
方法1:窗口函数实现(灵活性高)
SELECT TOP 25 customer FROM ( SELECT customer, -- 按客户分组,每组内按DocNum降序编号,rn=1对应该客户的最大DocNum记录 ROW_NUMBER() OVER (PARTITION BY customer ORDER BY DocNum DESC) AS rn FROM tt WHERE DocNum LIKE '%_%' AND UPPER(U_NAME) NOT LIKE '%E G%' ) AS sub_query WHERE rn = 1 ORDER BY DocNum DESC;
方法2:GROUP BY聚合实现
SELECT TOP 25 customer FROM ( SELECT customer, MAX(DocNum) AS max_docnum -- 找出每个客户的最大DocNum FROM tt WHERE DocNum LIKE '%_%' AND UPPER(U_NAME) NOT LIKE '%E G%' GROUP BY customer ) AS sub_query ORDER BY max_docnum DESC;
场景2:按记录DocNum降序遍历,收集25个不重复customer
如果需求是按记录的DocNum从大到小遍历,遇到新的customer就保留,直到凑够25个不重复值,可使用以下写法:
SELECT DISTINCT TOP 25 customer FROM ( SELECT customer, -- 按DocNum降序给所有记录排名,相同DocNum的记录排名一致 DENSE_RANK() OVER (ORDER BY DocNum DESC) AS rank_num FROM tt WHERE DocNum LIKE '%_%' AND UPPER(U_NAME) NOT LIKE '%E G%' ) AS sub_query ORDER BY rank_num;
内容的提问来源于stack exchange,提问作者wittream
相关产品推荐
相关产品推荐

