代码之家  ›  专栏  ›  技术社区  ›  hgulyan

如何在SQL Server中查找重复值

  •  9
  • hgulyan  · 技术社区  · 16 年前

    我正在使用SQL Server 2008。我有一张桌子

    Customers
    
    customer_number int
    
    field1 varchar
    
    field2 varchar
    
    field3 varchar
    
    field4 varchar
    

    …还有更多的专栏,这对我的查询不重要。

    客户号 是PK。我试图找到重复的值和它们之间的一些差异。

    请帮我找到所有相同的行

    1) 字段1、字段2、字段3、字段4

    2) 只有3列相等,其中一列不相等(列表1中的行除外)

    3) 只有两列相等,其中两列不相等(列表1和列表2中的行除外)

    最后,我将有3个具有此结果的表和附加的groupid,对于一组相似的表来说,它们是相同的(例如,对于3列等于,具有3列等于的行将是一个单独的组)。

    谢谢您。

    5 回复  |  直到 11 年前
        1
  •  4
  •   lc.    16 年前

    最简单的方法可能是编写一个存储过程,对每个具有重复项的客户组进行迭代,并分别为每个组编号插入匹配的客户组。

    不过,我已经考虑过了,您可能可以使用子查询来实现这一点。希望我没有使它变得比应该的更复杂,但是这会使您得到您正在寻找的第一个重复表(所有四个字段)。请注意,这是未经测试的,因此可能需要稍作调整。

    基本上,它获取有重复项的每一组字段,每个字段对应一个组编号,然后获取具有这些字段的所有客户,并分配相同的组编号。

    INSERT INTO FourFieldsDuplicates(group_no, customer_no)
    SELECT Groups.group_no, custs.customer_no
    FROM (SELECT ROW_NUMBER() OVER(ORDER BY c.field1) AS group_no,
                 c.field1, c.field2, c.field3, c.field4
          FROM Customers c
          GROUP BY c.field1, c.field2, c.field3, c.field4
          HAVING COUNT(*) > 1) Groups
    INNER JOIN Customers custs ON custs.field1 = Groups.field1
                               AND custs.field2 = Groups.field2
                               AND custs.field3 = Groups.field3
                               AND custs.field4 = Groups.field4
    

    另一个则要复杂一些,因为你需要扩大可能性。然后三个字段组将是:

    INSERT INTO ThreeFieldsDuplicates(group_no, customer_no)
    SELECT Groups.group_no, custs.customer_no
    FROM (SELECT ROW_NUMBER() OVER(ORDER BY GroupsInner.field1) AS group_no,
                 GroupsInner.field1, GroupsInner.field2, 
                 GroupsInner.field3, GroupsInner.field4
          FROM (SELECT c.field1, c.field2, c.field3, NULL AS field4
                FROM Customers c
                WHERE NOT EXISTS(SELECT d.customer_no
                           FROM FourFieldsDuplicates d
                           WHERE d.customer_no = c.customer_no)
                GROUP BY c.field1, c.field2, c.field3
                UNION ALL
                SELECT c.field1, c.field2, NULL AS field3, c.field4
                FROM Customers c
                WHERE NOT EXISTS(SELECT d.customer_no
                                 FROM FourFieldsDuplicates d
                                 WHERE d.customer_no = c.customer_no)
                GROUP BY c.field1, c.field2, c.field4
                UNION ALL
                SELECT c.field1, NULL AS field2, c.field3, c.field4
                FROM Customers c
                WHERE NOT EXISTS(SELECT d.customer_no
                                 FROM FourFieldsDuplicates d
                                 WHERE d.customer_no = c.customer_no)
                GROUP BY c.field1, c.field3, c.field4
                UNION ALL
                SELECT NULL AS field1, c.field2, c.field3, c.field4
                FROM Customers c
                WHERE NOT EXISTS(SELECT d.customer_no
                                 FROM FourFieldsDuplicates d
                                 WHERE d.customer_no = c.customer_no)
                GROUP BY c.field2, c.field3, c.field4) GroupsInner
          GROUP BY GroupsInner.field1, GroupsInner.field2, 
                   GroupsInner.field3, GroupsInner.field4
          HAVING COUNT(*) > 1) Groups
    INNER JOIN Customers custs ON (Groups.field1 IS NULL OR custs.field1 = Groups.field1)
                               AND (Groups.field2 IS NULL OR custs.field2 = Groups.field2)
                               AND (Groups.field3 IS NULL OR custs.field3 = Groups.field3)
                               AND (Groups.field4 IS NULL OR custs.field4 = Groups.field4)
    

    希望这会产生正确的结果,我会把最后一个留作练习。-D

        2
  •  56
  •   Pure.Krome    14 年前

    这是一个查找表中重复项的简便查询。假设您希望在一个表中查找存在多次的所有电子邮件地址:

    SELECT email, COUNT(email) AS NumOccurrences
    FROM users
    GROUP BY email
    HAVING ( COUNT(email) > 1 )
    

    您还可以使用此技术查找恰好发生一次的行:

    SELECT email
    FROM users
    GROUP BY email
    HAVING ( COUNT(email) = 1 )
    
        3
  •  2
  •   Lieven Keersmaekers    16 年前

    我不确定您是否需要对不同字段(如field1=field2)进行相等检查。
    否则这就足够了。

    编辑

    请随意调整测试数据,以便根据您的规格为我们提供错误输出的输入。

    测试数据

    DECLARE @Customers TABLE (
      customer_number INTEGER IDENTITY(1, 1)
      , field1 INTEGER
      , field2 INTEGER
      , field3 INTEGER
      , field4 INTEGER)
    
    INSERT INTO @Customers
              SELECT 1, 1, 1, 1
    UNION ALL SELECT 1, 1, 1, 1
    UNION ALL SELECT 1, 1, 1, NULL
    UNION ALL SELECT 1, 1, 1, 2
    UNION ALL SELECT 1, 1, 1, 3
    UNION ALL SELECT 2, 1, 1, 1
    

    所有平等

    SELECT  ROW_NUMBER() OVER (ORDER BY c1.customer_number)
            , c1.field1
            , c1.field2
            , c1.field3
            , c1.field4
    FROM    @Customers c1 
            INNER JOIN @Customers c2 ON c2.customer_number > c1.customer_number  
                                        AND ISNULL(c2.field1, 0) = ISNULL(c1.field1, 0) 
                                        AND ISNULL(c2.field2, 0) = ISNULL(c1.field2, 0)
                                        AND ISNULL(c2.field3, 0) = ISNULL(c1.field3, 0)
                                        AND ISNULL(c2.field4, 0) = ISNULL(c1.field4, 0)
    

    一个字段不同

    SELECT  ROW_NUMBER() OVER (ORDER BY field1, field2, field3, field4)
            , field1
            , field2
            , field3
            , field4
    FROM    (
              SELECT  DISTINCT c1.field1
                      , c1.field2
                      , c1.field3
                      , field4 = NULL
              FROM    @Customers c1 
                      INNER JOIN @Customers c2 ON c2.customer_number > c1.customer_number  
                                                 AND c2.field1 = c1.field1 
                                                 AND c2.field2 = c1.field2 
                                                 AND c2.field3 = c1.field3 
                                                 AND ISNULL(c2.field4, 0) <> ISNULL(c1.field4, 0) 
              UNION ALL
              SELECT  DISTINCT c1.field1
                      , c1.field2
                      , NULL
                      , c1.field4
              FROM    @Customers c1 
                      INNER JOIN @Customers c2 ON c2.customer_number > c1.customer_number  
                                                 AND c2.field1 = c1.field1 
                                                 AND c2.field2 = c1.field2 
                                                 AND ISNULL(c2.field3, 0) <> ISNULL(c1.field3, 0) 
                                                 AND c2.field4 = c1.field4 
              UNION ALL
              SELECT  DISTINCT c1.field1
                      , NULL
                      , c1.field3
                      , c1.field4
              FROM    @Customers c1 
                      INNER JOIN @Customers c2 ON c2.customer_number > c1.customer_number  
                                                 AND c2.field1 = c1.field1 
                                                 AND ISNULL(c2.field2, 0) <> ISNULL(c1.field2, 0) 
                                                 AND c2.field3 = c1.field3 
                                                 AND c2.field4 = c1.field4 
              UNION ALL
              SELECT  DISTINCT NULL
                      , c1.field2
                      , c1.field3
                      , c1.field4
              FROM    @Customers c1 
                      INNER JOIN @Customers c2 ON c2.customer_number > c1.customer_number  
                                                 AND ISNULL(c2.field1, 0) <> ISNULL(c1.field1, 0)
                                                 AND c2.field2 = c1.field2 
                                                 AND c2.field3 = c1.field3 
                                                 AND c2.field4 = c1.field4 
          ) c
    
        4
  •  0
  •   Pierre-Olivier Pignon    13 年前

    您可以简单地编写这样的代码来计算重复条目,我认为它是有效的:

    use *DATABASE_NAME*
    go
    SELECT     *YOUR_FIELD*, COUNT(*) AS dupes  
    FROM         *YOUR_TABLE_NAME*
    GROUP BY *YOUR_FIELD* 
    HAVING      (COUNT(*) > 1)
    

    享受

        5
  •  0
  •   Anon    11 年前

    有一种干净的方法可以做到这一点 CUBE() ,合计为 所有可能的组合 柱的

    SELECT
      field1,field2,field3,field4
     ,duplicate_row_count = COUNT(*)
     ,grp_id = GROUPING_ID(field1,field2,field3,field4)
    INTO #duplicate_rows
    FROM table_name
    GROUP BY CUBE(field1,field2,field3,field4)
    HAVING COUNT(*) > 1
      AND GROUPING_ID(field1,field2,field3,field4) IN (0,1,2,4,8,3,5,6,9,10,12)
    

    数字(0,1,2,4,8,3,5,6,9,10,12)只是我们关心的分组集的位掩码(0000000100100100,…,10101100),这些分组集与4、3或2匹配。

    然后使用一种将重复行中的空值作为通配符的技术将其连接回原始表。

    SELECT a.*
    FROM table_name a
    INNER JOIN #duplicate_rows b
      ON  NULLIF(b.field1,a.field1) IS NULL
      AND NULLIF(b.field2,a.field2) IS NULL
      AND NULLIF(b.field3,a.field3) IS NULL
      AND NULLIF(b.field4,a.field4) IS NULL
    --WHERE grp_id IN (0)             --Use this for 4 matches
    --WHERE grp_id IN (1,2,4,8)       --Use this for 3 matches
    --WHERE grp_id IN (3,5,6,9,10,12) --Use this for 2 matches
    
    推荐文章