SQL Server查询行:忽略重复userid及含NULL重复条目的问题
解决SQL Server中去重userid并排除全NULL用户的问题
看起来你之前的查询限制太严格啦——直接把所有带NULL的行都过滤掉,结果连那些只是部分行有NULL的用户(比如user4)和全是NULL的用户(比如user2)都一起排除了。咱们调整下逻辑,先明确核心需求:每个userid只返回一行,同时排除那些所有行的text和method都是NULL的用户,对吧?
下面给你两种实用的解决方案,都能满足需求:
方法一:用窗口函数(灵活可控,推荐)
这种方式可以让你精准控制优先返回哪一行(比如优先选text和method都非NULL的行):
WITH ranked_rows AS ( SELECT *, -- 给同一userid的行排名,优先保留text和method都不为NULL的行 ROW_NUMBER() OVER ( PARTITION BY userid ORDER BY CASE WHEN text IS NOT NULL AND method IS NOT NULL THEN 0 ELSE 1 END ) AS row_rank FROM property_table -- 先筛掉所有行都是text+method全NULL的用户(比如user2) WHERE EXISTS ( SELECT 1 FROM property_table pt2 WHERE pt2.userid = property_table.userid AND (pt2.text IS NOT NULL OR pt2.method IS NOT NULL) ) ) -- 取每个userid排名第一的行,实现去重 SELECT userid, text, method -- 建议明确列名,比用*更严谨 FROM ranked_rows WHERE row_rank = 1;
逻辑拆解:
EXISTS子查询:确保只保留那些至少有一行text或method不为NULL的用户,直接排除user2这类全NULL的用户。ROW_NUMBER()窗口函数:按userid分组,给每组的行排序——把text和method都非NULL的行设为最高优先级(排名0),其他行排名1,这样取第一行时会优先拿到有效数据。- 最后过滤出排名第一的行,就实现了userid去重,同时保留有效用户。
方法二:先筛选有效用户再关联
如果你觉得窗口函数有点复杂,这种方式更直观:
WITH valid_users AS ( -- 先找出所有至少有一行非全NULL的用户ID SELECT DISTINCT userid FROM property_table WHERE text IS NOT NULL OR method IS NOT NULL ) -- 对每个有效用户,取一行数据(优先选非NULL的行) SELECT pt.userid, pt.text, pt.method FROM valid_users vu CROSS APPLY ( SELECT TOP 1 * FROM property_table WHERE userid = vu.userid ORDER BY CASE WHEN text IS NOT NULL AND method IS NOT NULL THEN 0 ELSE 1 END ) pt;
逻辑拆解:
valid_usersCTE先拿到所有符合条件的用户ID,排除user2。CROSS APPLY对每个用户ID,从原表中取出一行数据,同样优先选择text和method都非NULL的行,实现去重。
为什么你之前的查询不行?
你之前的WHERE text is not NULL and method is not NULL是直接过滤掉所有text或method为NULL的行,这会导致:
- user2这类所有行都是NULL的用户,直接被全过滤;
- user4这类有一行是text为NULL、method有值的用户,这行也会被过滤,所以整个user4的数据都没了。
而咱们的方案是先保留用户(只要他们有至少一行非全NULL),再去重取行,这样就能兼顾user4这类情况了。
内容的提问来源于stack exchange,提问作者Sai
相关产品推荐
相关产品推荐

