当前位置: 首页 > 知识库问答 >
问题:

通过SELECT删除SQL重复项

张鸿宝
2023-03-14

我还有一个快速的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个答案

宋昕
2023-03-14

对于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

结果

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

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

如果希望所有行都具有最大信息量,可以将ROW_NUMBER替换为RANK。

这还考虑到V2和V3的权重相等,因此只有V2 NULL的行和只有V3 NULL的行是相等的。您可以通过更改CASE语句为这两个字段返回不同的值来更改该行为。i、 e.对于make NULL value 3和NON-NULL,其中一个值为0,另一个值为1,因此NON-NULL NON-NULL为Q=1,NULL NON-NULL为Q=3,NON-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不允许我们实际命名它。我的派生列是两个CASE语句的总和,因此它是一个整数值,表示该行中的null数。由于ORDER BY指令默认为升序,因此数据最多(空值最少)的行将具有最低的“Q”,并排序到顶部。

我给整个ROW\u NUMBER函数输出一个别名-“Quality”。它与我上面描述的“Q”不同,但它与之相关。质量将是一个整数序列,从1开始,每行增加1,而Q将是0、1或2,具体取决于行中有多少个空值。最低的Q行将获得最低质量的数字,但对于具有相同Q值的行,SQL将随机对其排序。

解决方案的最后一点是PARTITION BY子句,它告诉ROW_NUMBER(或RANK)函数将数据分解为集合(就像查询中的GROUP BY子句一样,它也可以包含1列或更多列)并重新开始对每个组进行编号。这样,Peter得到他自己的1,2,3,4,...质量值,Martin得到他自己的1,2,3,4,...值等。

因此,当我在查询末尾放置“WHERE质量=1”子句时,我是说“对于每个人,选择NULL最少的行”

我希望这就是你问的问题,我不确定我是否理解你的“如果我只是按1”位订购。

 类似资料:
  • 问题内容: 我需要从表中删除重复项: 该列是主键。 我想知道如何在有多次出现的情况下仅保留最大的 问题答案: 将订单更改为。

  • 问题内容: 如何从以以下方式设置的表中删除重复项? 一个工作人员可以有多个与他们相关联的type_ID,我想删除所有重复的类型。如果有重复项,我想删除具有最新条目的类型。 问题答案: 窗口函数row_number()的教科书候选: 这也照顾了一组相同的受骗者的情况。 请参阅有关data.SE的简化演示。 更新较简单的版本 事实证明,这可以简化:在SQL Server中,您可以直接从CTE中删除:

  • 我有一个整数和零的列表。我想只过滤掉Nones。 这将删除None,但也删除0(整数)。我想以保持0(整数)的方式修改它 结果是一个列表[1,0,1,0,1,0,1,0]--

  • 当我要执行以下查询时: 我得到了错误: 消息102,级别15,状态1,第1行“,”附近的语法不正确。 编辑: 我要删除klantId 3。

  • 我有下表(TBL_视频),在“TIMESTAMP”中有重复的列条目,我只想在“CAMERA”编号匹配时删除它们。 之前: 之后: 我已尝试此语句,但列不会相应删除。我非常感谢为生成正确的SQL语句所提供的所有帮助。提前谢谢!

  • 问题内容: 我有一个重复的表事务。我想保留具有最小id的记录,并基于四个字段DATE,AMOUNT,REFNUMBER,PARENTFOLDERID删除所有重复项。我写了这个查询,但是我不确定这是否可以有效地编写。您认为有更好的方法吗?我问是因为我担心运行时间。 问题答案: 做这样的事情可能会更有效