通过SELECT删除SQL重复项

时间:2014-08-05 12:14:38

标签: sql

我有另一个快速SQL问题。 请考虑下表:

Value1   |   Value2   |   Value3   
------------------------------------
Peter    |   Blue     |    Red
Peter    |   Null     |    Null
Martin   |   Blue     |    Null
Martin   |   Null     |    Null
Boris    |   Null     |    Null
Sergej   |   Null     |    Green
Sergej   |   Null     |    Null

你看这是一个特例。有些情况下,Value2和Value3都设置在一个条目中,有些情况下设置了Value2和Value3,并且有些情况下没有设置它们(没有重复)。

所以问题是:如何删除重复项(通过Value1)并获取信息最多的条目?即如果设置了Value2和/或Value3,则使用那些条目。很明显,我不能只使用“not null”,因为有些情况(那些没有重复的情况)我需要覆盖哪些都有Null。

第二个问题是我只有读取权限,因此必须在Select语句中进行。非常感谢你。

1 个答案:

答案 0 :(得分:1)

确定MS SQL会这样做

DECLARE @T TABLE (V1 VARCHAR(50), V2 VARCHAR(50), V3 VARCHAR(50))
INSERT INTO @T VALUES ('Peter', 'Blue', 'Red'), ('Peter', Null, Null), ('Martin', 'Blue',Null), 
    ('Martin', Null, Null), ('Boris', Null, Null), ('Sergej', Null, 'Green'), ('Sergej', Null, Null)
SElECT V1, V2, V3 
FROM (SELECT V1, V2, V3, ROW_NUMBER () 
          OVER (PARTITION BY V1 ORDER BY CASE WHEN V2 IS NULL THEN 1 ELSE 0 END 
                    + CASE WHEN V3 IS NULL THEN 1 ELSE 0 END) as Quality 
      FROM @T) as T
WHERE Quality = 1

<强> RESULT

V1       V2      V3  
Boris   NULL    NULL  
Martin  Blue    NULL  
Peter   Blue    Red  
Sergej  NULL    Green  

编辑:注意:这将为每个名称提供一个条目,即使有多行包含相同数量的信息。也就是说,如果Peter有两行在V2和V3中都具有非空值,系统将随机选择一行。

如果您想要所有具有最大信息量的行,您可以将ROW_NUMBER替换为RANK。

这也认为V2和V3具有相同的权重,因此只有V2 NULL的行和只有V3 NULL的行是相等的。您可以通过更改CASE语句来更改该行为,以返回2个字段的不同值。即,对于两个值为NULL且值为3的NON-NULL和另一个值为1的NON-NULL,因此NON-NULL NON-NULL为Q = 1,NULL NON-NULL为Q = 3,NON-NULL NULL为Q = 4,NULL NULL是Q = 6.

编辑2:在上面的解释中错误地使用NULL NULL两次: - (

编辑3:评论中要求的扩展说明
好没问题。 “ROW_NUMBER”(和RANK)函数通常会为数据集生成一系列数字。要知道订单应该基于什么,你必须告诉它。因此,这两个函数都需要“OVER(ORDER BY Col1 [,Col2 ...])”子句。 OVER()中的ORDER BY就像查询末尾的ORDER BY子句一样。

在这种情况下,我没有在您的数据中使用真正的列,我正在派生一个列(这是匿名的,我想为了清晰起见给它一个别名,但是SQL-Server 2008 R2没有支持)。作为参考,让我们调用派生列Q,即使SQL不会让我们实际命名它。我的派生列是2个CASE语句的总和,因此它是一个整数值,表示该行中的NULL数。由于ORDER BY指令默认为ASCENDING顺序,因此具有最多数据(最少的NULL)的行将具有最低的“Q”并排序到顶部。

我给整个ROW_NUMBER函数输出一个Alias - “Quality”。它与我上面描述的“Q”不同,但它与它有关。质量将是从1开始的整数序列,并且每行增加1,而Q将为0,1或2,具体取决于行中有多少NULL。最低Q行将获得最低质量数,但对于具有相同Q值的行,SQL将随机排序。

解决方案的最后一位是PARTITION BY子句,它告诉ROW_NUMBER(或RANK)函数将数据分解为集合(就像查询中的GROUP BY子句一样,它也可以占用1个或更多列并重新开始与每个组的编号。通过这种方式,彼得获得了他自己的1,2,3,4 ......质量价值,马丁获得了他自己的1,2,3,4 ......价值等。

所以当我在查询结尾处放置“WHERE Quality = 1”子句时,我说“对于每个人,选择具有最少NULL的行”

我希望你问的是这个问题,我不确定我是否理解你的“如果我只是简单地按1”。