【问题标题】:How do I find duplicates across multiple columns?如何跨多个列查找重复项?
【发布时间】:2011-12-30 06:09:39
【问题描述】:

所以我想在下面做这样的 sql 代码:

select s.id, s.name,s.city 
from stuff s
group by s.name having count(where city and name are identical) > 1

要生成以下内容,(但忽略仅名称或仅城市匹配的位置,它必须在两列上):

id      name  city   
904834  jim   London  
904835  jim   London  
90145   Fred  Paris   
90132   Fred  Paris
90133   Fred  Paris

【问题讨论】:

    标签: sql sql-server sql-server-2008 duplicates


    【解决方案1】:

    idnamecity 重复:

    select s.id, t.* 
    from [stuff] s
    join (
        select name, city, count(*) as qty
        from [stuff]
        group by name, city
        having count(*) > 1
    ) t on s.name = t.name and s.city = t.city
    

    【讨论】:

    • 请注意,如果namecity包含null,则在外层查询中报错,但在内层查询中匹配。
    • 如果值可能包含null,那么(除非我遗漏了什么)您需要将其更改为CROSS JOIN(完整的笛卡尔积),然后添加一个WHERE 子句,例如如:WHERE ((s.name = t.name) OR (s.name is null and t.name is null)) AND ((s.city = t.city) OR (s.city is null and t.city is null))
    • 此答案不会返回每个重复记录的唯一 ID。相反,它会将重复的记录合并为一条记录,然后选择表中最先出现的 ID。我相信@ssarabando 的答案是更合适的答案。
    • @Crayons 两个答案都将返回相同的结果。见dbfiddle.uk/…dbfiddle.uk/…
    【解决方案2】:
     SELECT name, city, count(*) as qty 
     FROM stuff 
     GROUP BY name, city HAVING count(*)> 1
    

    【讨论】:

    • 最干净的答案。
    • 这样你就无法知道每一行的id了。
    • SELECT name, city, count(*) as qty 替换为 SELECT * 以查看所有列,包括 id。
    • @yoyo 你的建议出错了;请建议完整的 SQL,它不会出错。
    • 还要查看(至少)ID 的最小/最大值:SELECT max(id), min(id), name, city, count(*) as qty FROM stuff GROUP BY name, city HAVING count(*)> 1
    【解决方案3】:

    这样的事情就可以解决问题。不知道性能,所以做一些测试。

    select
      id, name, city
    from
      [stuff] s
    where
    1 < (select count(*) from [stuff] i where i.city = s.city and i.name = s.name)
    

    【讨论】:

    • 这是一个被低估的答案,我相信这是最好的答案。此答案识别重复项,同时返回单个记录及其唯一 ID。标记的答案对结果进行分组,这意味着您实际上无法通过其唯一 ID 识别重复项,因此是一个不太有用的数据集。
    • @Crayons 两个答案都将返回相同的结果。见dbfiddle.uk/…dbfiddle.uk/…
    【解决方案4】:

    使用count(*) over(partition by...) 提供了一种简单有效的方法来定位不需要的重复,同时还列出所有受影响的行和所有想要的列:

    SELECT
        t.*
    FROM (
        SELECT
            s.*
          , COUNT(*) OVER (PARTITION BY s.name, s.city) AS qty
        FROM stuff s
        ) t
    WHERE t.qty > 1
    ORDER BY t.name, t.city
    

    虽然最新的 RDBMS 版本支持 count(*) over(partition by...) MySQL V 8.0 引入了“窗口函数”,如下所示(在 MySQL 8.0 中)

    CREATE TABLE stuff(
       id   INTEGER  NOT NULL
      ,name VARCHAR(60) NOT NULL
      ,city VARCHAR(60) NOT NULL
    );
    
    INSERT INTO stuff(id,name,city) VALUES 
      (904834,'jim','London')
    , (904835,'jim','London')
    , (90145,'Fred','Paris')
    , (90132,'Fred','Paris')
    , (90133,'Fred','Paris')
    
    , (923457,'Barney','New York') # not expected in result
    ;
    
    SELECT
        t.*
    FROM (
        SELECT
            s.*
          , COUNT(*) OVER (PARTITION BY s.name, s.city) AS qty
        FROM stuff s
        ) t
    WHERE t.qty > 1
    ORDER BY t.name, t.city
    
    编号 |姓名 |城市|数量 -----: | :--- | :----- | --: 90145 |弗雷德 |巴黎 | 3 90132 |弗雷德 |巴黎 | 3 90133 |弗雷德 |巴黎 | 3 904834 |吉姆 |伦敦 | 2 904835 |吉姆 |伦敦 | 2

    db小提琴here

    窗口函数。 MySQL 现在支持窗口函数,对于查询中的每一行,使用与相关的行执行计算 那一排。其中包括 RANK()、LAG() 和 NTILE() 等函数。 此外,几个现有的聚合函数现在可以用作 窗口函数;例如,SUM() 和 AVG()。了解更多信息, 见Section 12.21, “Window Functions”

    【讨论】:

      【解决方案5】:

      这篇文章有点晚了,但我发现这种方式非常灵活/高效

      select 
          s1.id
          ,s1.name
          ,s1.city 
      from 
          stuff s1
          ,stuff s2
      Where
          s1.id <> s2.id
          and s1.name = s2.name
          and s1.city = s2.city
      

      【讨论】:

      • select distinct ...可能是这里需要/缺少的,不是吗?
      【解决方案6】:

      您必须自行加入内容并匹配名称和城市。然后按计数分组。

      select 
         s.id, s.name, s.city 
      from stuff s join stuff p ON (
         s.name = p.city OR s.city = p.name
      )
      group by s.name having count(s.name) > 1
      

      【讨论】:

      • SQL Server 失败:所有非聚合列必须在 GROUP BY 中
      【解决方案7】:
      SELECT Feild1, Feild2, COUNT(*)
      FROM table name
      GROUP BY Feild1, Feild2
      HAVING COUNT(*)>1
      

      这会给你所有的答案。

      【讨论】:

        【解决方案8】:

        给定一个包含 70 列且只有 4 列表示重复的临时表, 此代码将返回有问题的列:

        SELECT 
            COUNT(*)
            ,LTRIM(RTRIM(S.TransactionDate)) 
            ,LTRIM(RTRIM(S.TransactionTime))
            ,LTRIM(RTRIM(S.TransactionTicketNumber)) 
            ,LTRIM(RTRIM(GrossCost)) 
        FROM Staging.dbo.Stage S
        GROUP BY 
            LTRIM(RTRIM(S.TransactionDate)) 
            ,LTRIM(RTRIM(S.TransactionTime))
            ,LTRIM(RTRIM(S.TransactionTicketNumber)) 
            ,LTRIM(RTRIM(GrossCost)) 
        HAVING COUNT(*) > 1
        

        .

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-09-05
          • 2011-08-01
          • 1970-01-01
          • 1970-01-01
          • 2018-03-11
          • 1970-01-01
          相关资源
          最近更新 更多