如何在SQL Server 2005中的一条语句中更新两个表?


193

我要一口气更新两个表。如何在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'

4
如果您解释原因,将会有所帮助。
埃里克·米克尔森

2
恐怕,SQL Server 2005不支持在一个查询中更新多个表。
2013年

Answers:


194

您不能在一个语句中更新多个表,但是,可以使用事务来确保两个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具有到table1的链接,但没有到table2的链接。如何更新表2的相同记录?我将如何链接?
Jango'1

@未知:根据您的评论,如果更新查询需要来自第三张表的键,则在更新表2时需要同时连接表1和表2。无论如何,您仍然需要执行两个单独的更新。
LBushkin

3
可能不相关:这在MYSQL上不起作用,因为mysql的更新语法不同。您必须去UPDATE Table1,Table2 SET Table1.LastName ='DR。XXXXXX'WHERE T1.id = T2.id
Juan Vilar

我们需要保持主键和它们之间的外键关系
SRINIVAS·高达

2
您还应该将更新语句放在try / catch块中,以避免在发生错误时进行部分更新。看到这个问题:stackoverflow.com/questions/1749719/…–
mechatroner

84

您不能一次更新两个表,但是可以使用将更新链接到插入中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'


这是最佳答案,应被投票为原始问题的真实答案。谢谢。它为我工作。
Fandango68年

1
T1.field应该是Table1.field吗?
WAF

22

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


2
天哪!对于更多的荣誉,我应该更频繁地使用“对不起”一词:P
Fandango68 '18年

14

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

更新(Transact-SQL)

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

创建视图(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子句的影响。
  • 在视图的select_statement中的任何位置都未将TOP与WITH CHECK OPTION子句一起使用。

不过,老实说,按照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.


1
尽管无法更新将影响多个表的View对象,但是您可以创建INSTEAD OF触发器,将原始对象分解为单独的语句(每个影响一个表):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

这适用于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'

如果要对需要多条语句的多个表进行更新……(如果您更新一个表,然后根据其他条件更新另一个表,则可能会发生这种情况……)应该使用事务。 


1
该分析器仍与其他用户相关。
Kyselejsyreček12

1
@Kyselejsyreček应该不惜一切代价避免这个答案。MySQL具有足够的怪癖和气味,实际​​上大多数不被支持,但保留它们是为了避免破坏依赖于那些怪癖的代码。升级很容易破坏它们,或者导致意外的行为和性能问题
Panagiotis Kanavos

7

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



0

从我的角度来看,您可以执行此操作,它是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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.