如何实现按指定列去重并带条件筛选图书数据的SQL查询?
解决图书数据按指定规则去重的SQL方案
嘿,我来帮你搞定这个图书数据的去重筛选问题!先理清楚你的核心需求:对于同一BookRef+BookFloor+BookSection+OrderType的分组,如果分组里有Orders不为空的行,就只保留这些非空行;如果分组里所有行的Orders都是空的,就只留其中一行。你的HAVING尝试没成功,主要是因为分组逻辑和筛选条件没匹配上需求,咱们换用窗口函数来实现会更灵活。
正确的SQL实现
这里用CTE结合窗口函数来完成筛选,逻辑清晰且符合需求:
WITH ranked_books AS ( SELECT BookRef, BookFloor, BookSection, Orders, OrderType, -- 标记当前分组(BookRef+BookFloor+BookSection+OrderType)是否存在非空Orders的行 MAX(CASE WHEN Orders IS NOT NULL THEN 1 ELSE 0 END) OVER (PARTITION BY BookRef, BookFloor, BookSection, OrderType) AS has_non_null_orders, -- 给分组内的行排序:非空Orders的行优先,空值行按任意顺序编号 ROW_NUMBER() OVER (PARTITION BY BookRef, BookFloor, BookSection, OrderType ORDER BY CASE WHEN Orders IS NOT NULL THEN 0 ELSE 1 END) AS rn FROM #myTempTable ) SELECT BookRef, BookFloor, BookSection, Orders, OrderType FROM ranked_books WHERE -- 分组有非空Orders时,只保留非空行 (has_non_null_orders = 1 AND Orders IS NOT NULL) -- 分组全是空Orders时,只保留第一行 OR (has_non_null_orders = 0 AND rn = 1);
代码逻辑解释
- CTE部分:
has_non_null_orders:通过窗口函数MAX统计当前分组内是否存在Orders非空的行,1表示有,0表示没有。rn:用ROW_NUMBER给分组内的行编号,把Orders非空的行排在最前面(CASE语句将非空值设为0,空值设为1,排序时0在前),空值行的编号从2开始。
- 筛选条件:
- 如果分组存在非空
Orders,就只保留那些Orders非空的行(对应你期望输出里OrderType=2的那一行)。 - 如果分组全是空
Orders,就只保留编号为1的那一行(也就是分组里的任意一行,比如OrderType=1、OrderType=3的行)。
- 如果分组存在非空
为什么你的HAVING语句没生效?
你的原查询把Orders也加入了GROUP BY,这会把同一OrderType下的空Orders和非空Orders分成不同的分组,完全偏离了“同一OrderType下筛选行”的需求;同时HAVING的条件逻辑也没有区分“是否存在非空Orders”的两种场景,所以没法得到正确的结果。
内容的提问来源于stack exchange,提问作者Ninita
相关产品推荐
相关产品推荐

