使用Distinct仍有重复行?如何在任意筛选条件成立时查询唯一行?
嘿,我懂你现在的糟心情况——明明加了DISTINCT,结果查出来还是一堆重复行,这大概率是多表左连接加上OR条件搞出来的笛卡尔积在捣乱!
为啥DISTINCT没用?
你的SQL里用了三次左连接,而且WHERE子句里的OR条件会悄悄改变左连接的逻辑(比如涉及eng表字段的条件,会把左连接变成类似内连接的效果)。更关键的是:如果eng或ref表中同一个DRAWING对应多条记录,连接后就会生成大量组合行。DISTINCT只能去掉完全一模一样的行,但只要eng.OP_PSI或者其他字段有差异,这些行就会被保留,看起来还是重复的。
解决方法,按需选一个就行
假设你要的是以DRAWING为唯一标识的不重复数据行,试试下面几种方案:
方案一:先筛选符合条件的DRAWING,再关联表
先把满足筛选条件的DRAWING单独拎出来,再和其他表关联,避免过早连接产生冗余:
SELECT r.DRAWING, r.[DESC], r.CF3 AS rCF3, e.OP_PSI FROM ( -- 先找出所有符合条件的DRAWING,去重 SELECT DISTINCT t.DRAWING FROM thk t LEFT JOIN eng e ON e.DRAWING = t.DRAWING WHERE t.SurveyNumber = @SurveyNumber OR CAST(e.L_RATE AS DECIMAL(10,0)) >= 14 OR CAST(e.S_RATE AS DECIMAL(10,0)) >= 14 OR (YEAR(GETDATE()) - YEAR(t.LastModifiedDate) >= 5) -- 补全你没写完的时间条件 ) AS filtered_drawings LEFT JOIN ref r ON r.DRAWING = filtered_drawings.DRAWING LEFT JOIN eng e ON e.DRAWING = filtered_drawings.DRAWING -- 如果eng表一个DRAWING有多条记录,这里可以用聚合函数取一个值,比如MAX(e.OP_PSI) GROUP BY r.DRAWING, r.[DESC], r.CF3, e.OP_PSI
方案二:用窗口函数精准去重,保留每个DRAWING的一条记录
如果eng表同一个DRAWING有多个记录,你可以指定保留哪一条(比如OP_PSI最大的、最新的):
WITH ranked_data AS ( SELECT r.DRAWING, r.[DESC], r.CF3 AS rCF3, e.OP_PSI, -- 按DRAWING分组,给每条记录排名,排序规则可以按需改 ROW_NUMBER() OVER (PARTITION BY r.DRAWING ORDER BY e.OP_PSI DESC) AS rn FROM thk t LEFT JOIN eng e ON e.DRAWING = t.DRAWING LEFT JOIN ref r ON r.DRAWING = t.DRAWING WHERE t.SurveyNumber = @SurveyNumber OR CAST(e.L_RATE AS DECIMAL(10,0)) >= 14 OR CAST(e.S_RATE AS DECIMAL(10,0)) >= 14 OR (YEAR(GETDATE()) - YEAR(t.LastModifiedDate) >= 5) ) SELECT DRAWING, [DESC], rCF3, OP_PSI FROM ranked_data WHERE rn = 1 -- 只取每个DRAWING的第一条记录
方案三:调整连接逻辑,用聚合避免笛卡尔积
如果ref表的DRAWING本身是唯一的,可以以ref为主表,关联满足条件的thk和eng,同时对eng的字段做聚合:
SELECT r.DRAWING, r.[DESC], r.CF3 AS rCF3, MAX(e.OP_PSI) AS OP_PSI -- 用MAX/MIN取一个合适的OP_PSI值,按需调整 FROM ref r LEFT JOIN thk t ON r.DRAWING = t.DRAWING LEFT JOIN eng e ON r.DRAWING = e.DRAWING WHERE t.SurveyNumber = @SurveyNumber OR CAST(e.L_RATE AS DECIMAL(10,0)) >= 14 OR CAST(e.S_RATE AS DECIMAL(10,0)) >= 14 OR (YEAR(GETDATE()) - YEAR(t.LastModifiedDate) >= 5) GROUP BY r.DRAWING, r.[DESC], r.CF3
小提醒
如果你的筛选条件里涉及左连接表的字段(比如e.L_RATE),左连接会自动变成内连接——因为NULL值无法满足>=14的条件。如果需要保留thk中没有对应eng记录但满足其他条件的行,可以把部分条件移到ON子句里,比如:
LEFT JOIN eng e ON e.DRAWING = t.DRAWING AND (CAST(e.L_RATE AS DECIMAL(10,0)) >= 14 OR CAST(e.S_RATE AS DECIMAL(10,0)) >= 14)
内容的提问来源于stack exchange,提问作者GoGetSOme




