【问题标题】:How do I update a table that references duplicate records?如何更新引用重复记录的表?
【发布时间】:2021-03-28 03:12:37
【问题描述】:

我有两个 SQL 表。一个人从另一个存储模块列表及其 ID 的表中获取参考值。但这些描述并不是唯一的。我正在尝试删除表 A 的重复项,但我不确定如何更新表 B 以仅引用单个值。

例子:

Table A:                                      Table B:

--------------------------------            ------------------------------------
ID      Description      RefID               ID            Name       
--------------------------------            ------------------------------------
1       Test 1           2                   1            QuickReports
--------------------------------            ------------------------------------
2       Test 2           1                   2            QuickReports
--------------------------------            ------------------------------------

我希望结果如下:

Table A:                                      Table B:

--------------------------------            ------------------------------------
ID      Description      RefID               ID            Name       
--------------------------------            ------------------------------------
1       Test 1           1                   1            QuickReports
--------------------------------            ------------------------------------
2       Test 2           1                  
--------------------------------        

我设法使用以下代码从表 B 中删除了重复项,但我无法更新表 A 中的记录。每个表都有超过 500 条记录。

WITH cte AS(
    SELECT 
        Name,
    ROW_NUMBER() OVER (
        PARTITION BY
            Name
        ORDER BY 
            Name
        )row_num
    FROM ReportmodulesTest
)
    DELETE FROM cte
    WHERE row_num > 1;  

【问题讨论】:

    标签: sql sql-server duplicates sql-update inner-join


    【解决方案1】:

    您需要先更新表 A,然后再从表 B 中删除。

    您标记了您的问题 MySQL,但该数据库不支持您显示的 delete 语句。我怀疑您正在运行 SQL Server,所以这里是如何在 that 数据库中执行此操作:

    update a
    set refid = b.minid
    from tablea
    inner join (select name, id, min(id) over(partition by name) minid from tableb) b 
        on b.id = a.id and b.minid <> a.id
    

    在 MySQL 中,您可以将相同的查询表述为:

    update tablea a
    from tablea
    inner join (select name, id, min(id) over(partition by name) minid from tableb) b on b.id = a.id
    set a.refid = b.minid
    where b.minid <> a.id
    

    【讨论】:

      【解决方案2】:

      您可以使用以下方法更新第一个表:

      update a join
             (select b.*,
                     min(id) over (partition by name) as min_id
              from b
             ) b
             on a.refid = b.id
          set a.refid = b.min_id
          where a.refid <> b.min_id;
      

      然后,您可以使用类似的逻辑删除第二个表中的行:

      delete b
          from b join
               (select b.*,
                       min(id) over (partition by name) as min_id
                from b
               ) bb
               on bb.id = b.id
          where b.id <> bb.min_id;
      

      【讨论】:

        【解决方案3】:

        我找到了一个使这个过程变得更容易的解决方案。我首先使用Row_Number 查找表A 中的重复项,并使用SELECT INTO 一个临时表。

        SELECT
               a.Id
             , a.Name
             , ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Id DESC) RN
        INTO
             #TestTable
        FROM
             TableA a WITH(NOLOCK)
        

        然后我 JOIN 表 A 和表 B 来查看 ID 匹配的位置并确定我需要保留哪个 ID 以及我需要删除哪个 ID:

        SELECT
               b.Id
             , b.Name
             , b.RefId
             , ToKeep.Id   KeepId
             , ToDelete.Id DeleteId
        FROM
             #TestTable ToDelete
             JOIN TableB b WITH(NOLOCK)
                ON b.RefId = ToDelete.Id
             JOIN #TestTable ToKeep
                ON ToDelete.Name = ToKeep.Name
                   AND ToKeep.RN = 1
        WHERE ToDelete.RN > 1
        

        然后使用类似的语句,我只是更新记录:

        UPDATE b
        SET
            b.RefId = ToKeep.Id,
        FROM #TestTable ToDelete
             JOIN TableB b WITH(NOLOCK)
                ON b.RefId = ToDelete.Id
             JOIN #TestTable ToKeep
                ON ToDelete.Name = ToKeep.Name
                   AND ToKeep.RN = 1
        WHERE
              ToDelete.RN > 1
        

        最后,我现在可以删除重复记录了:

        DELETE a
        FROM #TestTable b
             INNER JOIN TableA a
                ON b.Id = a.Id
        WHERE
              b.RN > 1
        

        在此之后,您可以使用相同的第一个SELECT 语句来确保删除所有重复项。只需删除 SELECT INTO 语句即可。

        感谢我的一位匿名同事提供此解决方案,并希望这对那里的人有所帮助。

        【讨论】:

          猜你喜欢
          • 2013-12-05
          • 1970-01-01
          • 2013-07-18
          • 2017-06-12
          • 1970-01-01
          • 2021-05-17
          • 2020-04-08
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多