【问题标题】:SQL UPDATE Self-join with compound matching value具有复合匹配值的 SQL UPDATE 自联接
【发布时间】:2014-04-02 23:46:28
【问题描述】:

我有一个包含行的 MSSQL 表,我需要更新其中的一些行,具体取决于同一个表中是否存在其他行。表格和示例数据如下所示:

SQL 表:

    TABLE tblConnector(
      ID1 [int] NOT NULL,
      ID2 [int] NOT NULL,
      ID3 [int] NOT NULL,
      ...other cols...)

具有由 ID1、ID2 和 ID3 组成的主键集群 - 意味着复合键必须是唯一的。

数据结构:

ID1  ID2  ID3

111  222  1
111  222  9999
333  444  1    <--- update only this row
555  666  1        
555  666  9999
777  888  2
777  888  9999 
123  456  3    <--- don't update this row

我需要更新此表中的任何行,设置 ID3 = 9999,其中 ID3 当前为 1,并且表中没有其他行具有相同的 ID1 和 ID2 值,ID3 = 9999。

在我的示例数据中,我只想更新第 3 行,设置 ID3 = 9999 - 因为它的 ID3 = 1 并且表中没有其他行具有相同的 ID1 和 ID2 值(其中 ID3 1 )。我不想更新最后一行 - 所以使用 count() 来隔离行不是一种有效的方法。

我已经尝试了无数次尝试将表连接到自身,但我似乎无法获得只会影响我想要的行的 UPDATE 语句。

关于如何编写此 SQL 的任何建议?

更新:我应该更清楚 - 如果 ID3 中的当前值为 1,我想将 ID3 列更新为 9999 ONLY ...并且有没有其他具有相同 ID1 和 ID2 值且 ID3 = 9999 的行。ID1、ID2 和 ID3 组成一个唯一键,并且在 ID3 中设置 9999 不能复制已经存在的键值。

【问题讨论】:

    标签: sql-server sql-update multiple-columns self-join


    【解决方案1】:

    也许我的阅读方式不同。

    ;WITH cte AS (
      SELECT ID1, ID2
        FROM tblConnector
       GROUP BY ID1, ID2
      HAVING COUNT(1) = 1
    )
    UPDATE tblConnector 
       SET ID3 = 9999
      FROM tblConnector a
           INNER JOIN
           cte b ON a.ID1 = b.ID1
                AND a.ID2 = b.ID2
    

    sqlfiddle

    编辑(评论后)

    将您的新示例记录和 WHERE ID3 = 1 添加到 UPDATE。在这种情况下,1 是您想要插入的任何单个值的占位符。

    ;WITH cte AS (
      SELECT ID1, ID2
        FROM tblConnector
       GROUP BY ID1, ID2
      HAVING COUNT(1) = 1
    )
    UPDATE tblConnector 
       SET ID3 = 9999
      FROM tblConnector a
           INNER JOIN
           cte b ON a.ID1 = b.ID1
                AND a.ID2 = b.ID2
     WHERE ID3 = 1
    

    New fiddle

    【讨论】:

    • 虽然您的解决方案适用于我最初提供的有限示例数据,但不需要按计数过滤要更新的行,因为我只想更新 ID3 中具有特定值的行,如所述上面,在我的更新中。如果有一个唯一的 ID1、ID2 值行且 ID3 = 2(例如),我不想更新该行。
    • 嗯。也许只是添加 WHERE ID3 = 1 ——或者你对更新的具体价值是什么?编辑待定。
    【解决方案2】:

    按照您的确切措辞,以下应该有效:

    UPDATE tblConnector t1
    SET ID3 = 9999
    WHERE NOT EXISTS
    (
        SELECT 1
        FROM tblConnector t2
        WHERE t2.ID1 = t1.ID1
        AND t2.ID2 = t1.ID2
        AND t2.ID3 <> 9999
    )
    

    【讨论】:

    • 我认为更新表上的别名需要编码为 UPDATE t1 SET ID3 = 999 FROM tblConnector t1 ... SQL 验证器不喜欢提供的语法。
    • 我也试过这种方式,但它没有更新我需要的行: UPDATE t1 SET t1.ID3 = 9999 FROM tblConnector t1 WHERE NOT EXISTS ( SELECT 1 FROM tblConnector t2 WHERE t2.ID1 = t1.ID1 AND t2.ID2 = t1.ID2 AND t2.ID3 9999)
    【解决方案3】:

    没有EXISTS,没有CTE 方法。我不知道这是否最有效。

    update t1
    set t1.id3 = 9999 
    --select *
    from
    tblConnector as t1 
    left join
    (
    select id1, id2, COUNT(id1) as Rowz
    from tblConnector as t2
    group by id1, id2
    ) as src
    on t1.id1 = src.id1
    where Rowz = 1
    

    【讨论】:

    • 我用了同样的方法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-28
    • 2017-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多