【问题标题】:How to update two tables in one statement in SQL Server 2005?如何在 SQL Server 2005 的一个语句中更新两个表?
【发布时间】:2011-01-03 21:46:30
【问题描述】:

我想一次更新两个表。我如何在 SQL Server 2005 中做到这一点?

UPDATE 
  Table1, 
  Table2
SET 
  Table1.LastName='DR. XXXXXX', 
  Table2.WAprrs='start,stop'
FROM 
  Table1 T1, 
  Table2 T2
WHERE 
  T1.id = T2.id
AND 
  T1.id = '010008'

【问题讨论】:

标签: sql sql-server sql-server-2005 tsql


【解决方案1】:

您不能在一个语句中更新多个表,但是,您可以使用事务来确保两个UPDATE 语句被原子处理。您还可以对它们进行批处理以避免往返。

BEGIN TRANSACTION;

UPDATE Table1
SET Table1.LastName = 'DR. XXXXXX' 
FROM Table1 T1, Table2 T2
WHERE T1.id = T2.id
and T1.id = '011008';

UPDATE Table2
SET Table2.WAprrs = 'start,stop'
FROM Table1 T1, Table2 T2
WHERE T1.id = T2.id
and T1.id = '011008';

COMMIT;

【讨论】:

  • 实际上,我正在从另一个 temptable 更新这两个表的记录。 temptable 具有指向 table1 但没有指向 table2 的链接。如何更新 Table2 的相同记录?我将如何链接它?
  • @unknown:根据您的评论,如果您的更新查询需要来自第三个表的键,则在更新 Table2 时,您需要同时连接 Table1 和 Table2。无论如何,您仍然需要进行两次单独的更新。
  • 可能不相关:这在 MYSQL 上不起作用,因为 mysql 的更新语法不同。你必须去 UPDATE Table1 , Table2 SET Table1.LastName = 'DR. XXXXXX' WHERE T1.id = T2.id
  • 是否需要维护它们之间的主键和外键关系
  • 您还应该将更新语句放在 try/catch 块中,以避免出现错误时部分更新。看到这个问题:stackoverflow.com/questions/1749719/…
【解决方案2】:

对于基于 Table2 特定列的一般更新 table1 特定列,此查询完美运行:

UPDATE table 1  
SET Col 2 = t2.Col2,  
    Col 3 = t2.Col3  
FROM table1 t1  
INNER JOIN table 2 t2 ON t1.Col1 = t2.col1 

【讨论】:

    【解决方案3】:

    您不能同时更新两个表,但您可以使用OUTPUT INTO 将更新链接到插入,并且您可以将此输出用作第二次更新的连接:

    DECLARE @ids TABLE (id int);
    BEGIN TRANSACTION
    
    UPDATE Table1 
    SET Table1.LastName = 'DR. XXXXXX'  
    OUTPUT INSERTED.id INTO @ids
    WHERE Table1.field = '010008';
    
    UPDATE Table2 
    SET Table2.WAprrs = 'start,stop' 
    FROM Table2 
    JOIN @ids i on i.id = Table2.id;
    
    COMMIT;
    

    我将您的示例 WHERE 条件更改为 id 以外的其他字段。如果是id,你就不需要这个花哨的OUTPUT,你可以只用UPDATE第二张桌子换成同样的id='010008'

    【讨论】:

    • 这是最佳答案,应该被选为原始问题的真实答案。谢谢你。它对我有用。
    • 那个T1.field应该是Table1.field吗?
    【解决方案4】:

    从我的角度来看,您可以这样做,它在 SQL SERVER 中对两个表进行一对一的更新:

     BEGIN TRANSACTION
    
          DECLARE @CNSREQ VARCHAR(30)
          DECLARE @ID INT
          DECLARE @CNSRQDT VARCHAR(30)
          DECLARE @ID2 INT
    
          DECLARE @IDCNSREQ INT
          DECLARE @FINALCNSREQ VARCHAR(30)
          DECLARE @FINALCNSRQDT VARCHAR(30)
          DECLARE @IDCNSRQDT INT
    
    
          SET @CNSREQ=(SELECT MIN(REQUISICIONESDT.CNSREQ) FROM REQUISICIONESDT
              INNER JOIN 
                  REQUISICIONES
                    ON REQUISICIONESDT.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
               AND REQUISICIONES.CNSREQ = REQUISICIONESDT.CNSREQ AND REQUISICIONESDT.IDREQ = REQUISICIONES.ID
            WHERE REQUISICIONES.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID)
    
          SELECT REQUISICIONES.CNSREQ, REQUISICIONES.ID, REQUISICIONES.CNSRQDT FROM REQUISICIONES
           INNER JOIN 
              REQUISICIONESDT
                  ON REQUISICIONESDT.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
                   AND REQUISICIONES.CNSREQ = REQUISICIONESDT.CNSREQ AND REQUISICIONESDT.IDREQ = REQUISICIONES.ID
            WHERE REQUISICIONES.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
        AND REQUISICIONES.CNSREQ = @CNSREQ
    
            UPDATE REQUISICIONESDT SET  REQUISICIONESDT.CNSREQ=NULL, REQUISICIONESDT.IDREQ=NULL
              FROM REQUISICIONES INNER JOIN REQUISICIONESDT
                 ON REQUISICIONESDT.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
           WHERE REQUISICIONES.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
          AND REQUISICIONES.CNSREQ = @CNSREQ
    
            UPDATE REQUISICIONES SET REQUISICIONES.CNSRQDT=NULL, REQUISICIONES.IDRQDT=NULL
              FROM REQUISICIONES INNER JOIN REQUISICIONESDT
              ON REQUISICIONESDT.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
           WHERE REQUISICIONES.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
         AND REQUISICIONES.CNSREQ = @CNSREQ
    
           SET @ID2=(SELECT MIN(REQUISICIONESDT.ID) FROM REQUISICIONESDT
            WHERE ISNULL(REQUISICIONESDT.IDREQ,0)<>0)
         DELETE FROM REQUISICIONESDT WHERE REQUISICIONESDT.ID=@ID2
    
    
          SET @IDCNSREQ=(SELECT MIN (REQUISICIONES.ID)FROM REQUISICIONES
              INNER JOIN REQUISICIONESDT ON
            REQUISICIONESDT.CEDULA = REQUISICIONES.CEDULA AND REQUISICIONES.FECHA_SOLICITUD = REQUISICIONESDT.FECHA_SOLICITUD
             WHERE REQUISICIONES.CNSRQDT IS NULL AND REQUISICIONES.IDRQDT IS NULL)
    
            SET @FINALCNSREQ=(SELECT MIN (REQUISICIONES.CNSREQ)FROM REQUISICIONES
                INNER JOIN REQUISICIONESDT ON
            REQUISICIONESDT.CEDULA = REQUISICIONES.CEDULA AND REQUISICIONES.FECHA_SOLICITUD = REQUISICIONESDT.FECHA_SOLICITUD
             WHERE REQUISICIONES.CNSRQDT IS NULL AND REQUISICIONES.IDRQDT IS NULL)
    
             SET @FINALCNSRQDT=(SELECT MIN(REQUISICIONESDT.CNSRQDT) FROM REQUISICIONES
               INNER JOIN REQUISICIONESDT ON
              REQUISICIONESDT.CEDULA = REQUISICIONES.CEDULA AND REQUISICIONES.FECHA_SOLICITUD = REQUISICIONESDT.FECHA_SOLICITUD
               WHERE REQUISICIONES.CNSRQDT IS NULL AND REQUISICIONES.IDRQDT IS NULL)
    
              SET @IDCNSRQDT=(SELECT MIN (REQUISICIONESDT.ID)FROM REQUISICIONES
               INNER JOIN REQUISICIONESDT ON
             REQUISICIONESDT.CEDULA = REQUISICIONES.CEDULA AND REQUISICIONES.FECHA_SOLICITUD = REQUISICIONESDT.FECHA_SOLICITUD  
             WHERE REQUISICIONES.CNSRQDT IS NULL AND REQUISICIONES.IDRQDT IS NULL)
    
               UPDATE REQUISICIONES SET REQUISICIONES.CNSRQDT = @FINALCNSRQDT, REQUISICIONES.IDRQDT=@IDCNSRQDT FROM REQUISICIONES
                INNER JOIN REQUISICIONESDT ON
                 REQUISICIONESDT.CEDULA = REQUISICIONES.CEDULA AND REQUISICIONES.FECHA_SOLICITUD = REQUISICIONESDT.FECHA_SOLICITUD
                WHERE REQUISICIONESDT.CNSRQDT = @FINALCNSRQDT AND REQUISICIONESDT.ID = @IDCNSRQDT 
    
    
    ROLLBACK TRANSACTION
    

    【讨论】:

      【解决方案5】:

      就像下面这个查询一样简单。

      UPDATE 
        Table1 T1 join Table2 T2 on T1.id = T2.id
      SET 
        T1.LastName='DR. XXXXXX', 
        T2.WAprrs='start,stop'
      WHERE 
        T1.id = '010008'
      

      【讨论】:

        【解决方案6】:

        您可以为 一个表 编写 update 语句,然后在 first table 更新时编写一个触发器,从而更新第二张桌子

        【讨论】:

          【解决方案7】:

          这适用于 MySQL,实际上只是一个隐式事务,但它应该是这样的:

          UPDATE Table1 t1, Table2 t2 SET 
          t2.field = t2.field+2,
          t1.field = t1.field+2
          
          WHERE t1.id = t2.foreign_id and t2.id = '123414'
          

          如果您要对需要多条语句的多个表进行更新……如果您更新一个,然后根据其他条件更新另一个……您应该使用事务。

          【讨论】:

          • 此分析器仍然与其他用户相关。
          • @Kyselejsyreček 应该不惜一切代价避免这个答案。 MySQL 有足够多的怪癖和异味,其中大部分实际上不受支持,但保留下来以避免破坏依赖于这些怪癖的代码。升级很容易破坏它们或导致意外的行为和性能问题
          【解决方案8】:

          对此的简短回答是否定的。虽然您可以在更新语句的from 子句中输入多个表,但您只能在update 关键字之后指定单个表。即使您确实编写了一个“可更新”视图(它只是一个遵循某些限制的视图),这样的更新也会失败。以下是 MSDN 文档中的相关剪辑(重点是我的)。

          UPDATE (Transact-SQL)

          table_or_view_name 引用的视图必须是可更新的,并且在视图的 FROM 子句中引用恰好一个基表。有关可更新视图的详细信息,请参阅 CREATE VIEW (Transact-SQL)。

          CREATE VIEW (Transact-SQL)

          只要满足以下条件,就可以通过视图修改底层基表的数据:

          • 任何修改,包括 UPDATE、INSERT 和 DELETE 语句,都必须引用仅一个基表中的列。
          • 视图中被修改的列必须直接引用表列中的基础数据。这些列不能以任何其他方式派生,例如通过以下方式:
            • 聚合函数:AVG、COUNT、SUM、MIN、MAX、GROUPING、STDEV、STDEVP、VAR 和 VARP。
            • 计算。无法从使用其他列的表达式计算该列。使用集合运算符 UNION、UNION ALL、CROSSJOIN、EXCEPT 和 INTERSECT 形成的列相当于计算,并且也不可更新。
          • 正在修改的列不受 GROUP BY、HAVING 或 DISTINCT 子句的影响。
          • TOP 不与 WITH CHECK OPTION 子句一起在视图的 select_statement 中的任何地方使用。

          不过,老实说,您应该考虑按照 LBushkin 的示例在事务中使用两个不同的 SQL 语句。

          更新:我最初断言您可以在可更新视图中更新多个表是错误的。在 SQL Server 2005 & 2012 上,它会产生以下错误。我已更正我的答案以反映这一点。

          Msg 4405, Level 16, State 1, Line 1

          View or function 'updatable_view' is not updatable because the modification affects multiple base tables.

          【讨论】:

          • 虽然无法更新会影响多个表的 View 对象,但您可以创建 INSTEAD OF triggers 将原始语句分成单独的语句(每个语句影响一个表):INSTEAD OF Specifies that the DML trigger is executed instead of the triggering SQL statement, therefore, overriding the actions of the triggering statements. INSTEAD OF cannot be specified for DDL or logon triggers.
          【解决方案9】:

          你应该在一个事务中放置两个更新语句

          【讨论】:

            【解决方案10】:

            对不起,afaik,你不能那样做。要更新两个不同表中的属性,您需要执行两个单独的语句。但是它们可以是成批的(一组SQL一次往返发送到服务器)

            【讨论】:

            • 天哪!我应该更频繁地使用对不起这个词来获得额外的荣誉:P
            猜你喜欢
            • 1970-01-01
            • 2014-03-25
            • 2018-03-11
            • 1970-01-01
            • 2016-06-10
            • 1970-01-01
            • 2011-02-18
            • 1970-01-01
            • 2012-12-21
            相关资源
            最近更新 更多