Como atualizar duas tabelas em uma instrução no SQL Server 2005?

193

Eu quero atualizar duas tabelas de uma só vez. Como faço isso no 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'
Jango
fonte
4
Ajudaria se você explicasse o porquê.
Eric Mickelsen
2
Receio que o SQL Server 2005 não suporte a atualização de várias tabelas em uma consulta.
Pranav Singh

Respostas:

194

Você não pode atualizar várias tabelas em uma instrução, no entanto, pode usar uma transação para garantir que duas UPDATEinstruções sejam tratadas atomicamente. Você também pode agrupá-los para evitar uma viagem de ida e volta.

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;
LBushkin
fonte
Na verdade, estou atualizando os registros dessas duas tabelas de outra tentadora. Tentable tem link para table1, mas não table2. Como posso atualizar o mesmo registro da Tabela2? Como vou vinculá-lo?
Jango
@ desconhecido: Com base no seu comentário, você precisaria ingressar na Tabela1 e na Tabela2 quando atualizar a Tabela2 se a sua consulta de atualização precisar das chaves de uma terceira tabela. Independentemente disso, você ainda precisa fazer duas atualizações separadas.
precisa saber é o seguinte
3
provavelmente não está relacionado: isso não funcionará no MYSQL porque a sintaxe de atualização para o mysql é diferente. você teria que ir UPDATE Table1, Table2 SET Table1.LastName = 'DR. XXXXXX 'WHERE T1.id = T2.id
Juan Vilar
precisamos manter chave primária e relação de chave estrangeira entre eles
gowda srinivas
2
Você também deve colocar suas instruções de atualização dentro do bloco try / catch para evitar atualizações parciais em caso de erro. veja esta pergunta: stackoverflow.com/questions/1749719/…
mechatroner 3/17
84

Você não pode atualizar duas tabelas ao mesmo tempo, mas pode vincular uma atualização a uma inserção usando OUTPUT INTOe pode usar esta saída como uma junção para a segunda atualização:

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;

Alterei sua WHEREcondição de exemplo para outro campo que não id. Se idvocê não precisa dessa fantasia OUTPUT, pode apenas UPDATEa segunda tabela para a mesma coisa id='010008'.

Remus Rusanu
fonte
Esta é a melhor resposta e deve ser votada como a verdadeira resposta à pergunta original. Obrigado. Funcionou para mim.
Fandango68
1
Isso T1.fielddeveria ser Table1.field?
WAF
22

Desculpe, você não pode fazer isso. Para atualizar atributos em duas tabelas diferentes, você precisará executar duas instruções separadas. Mas eles podem estar em um lote (um conjunto de SQL enviado ao servidor em uma ida e volta)

Charles Bretana
fonte
2
Poxa! Eu deveria usar a palavra Desculpe mais freqüência para elogios extras: P
Fandango68
14

A resposta curta para isso é não. Embora você possa inserir várias tabelas na fromcláusula de uma instrução de atualização, você pode especificar apenas uma única tabela após a updatepalavra - chave. Mesmo se você escrever uma visão "atualizável" (que é simplesmente uma visão que segue certas restrições), atualizações como essa falharão. Aqui estão os clipes relevantes da documentação do MSDN (a ênfase é minha).

ATUALIZAÇÃO (Transact-SQL)

A visualização referenciada por table_or_view_name deve ser atualizável e referenciar exatamente uma tabela base na cláusula FROM da visualização. Para obter mais informações sobre visualizações atualizáveis, consulte CREATE VIEW (Transact-SQL).

CRIAR VISTA (Transact-SQL)

Você pode modificar os dados de uma tabela base subjacente por meio de uma exibição, desde que as seguintes condições sejam verdadeiras:

  • Quaisquer modificações, incluindo as instruções UPDATE, INSERT e DELETE, devem fazer referência a colunas de apenas uma tabela base .
  • As colunas que estão sendo modificadas na visualização devem fazer referência direta aos dados subjacentes nas colunas da tabela. As colunas não podem ser derivadas de nenhuma outra maneira, como por exemplo:
    • Uma função agregada: AVG, COUNT, SUM, MIN, MAX, GROUPING, DESVPAD, DESVPADP, VAR e VARP.
    • Uma computação. A coluna não pode ser calculada a partir de uma expressão que usa outras colunas. As colunas formadas usando os operadores de conjunto UNION, UNION ALL, CROSSJOIN, EXCEPT e INTERSECT somam um cálculo e também não são atualizáveis.
  • As colunas que estão sendo modificadas não são afetadas pelas cláusulas GROUP BY, HAVING ou DISTINCT.
  • TOP não é usado em nenhum lugar da declaração select_ da exibição junto com a cláusula WITH CHECK OPTION.

Com toda a honestidade, porém, você deve considerar o uso de duas instruções SQL diferentes em uma transação, conforme o exemplo de LBushkin.

ATUALIZAÇÃO: Minha afirmação original de que era possível atualizar várias tabelas em uma exibição atualizável estava errada. No SQL Server 2005 e 2012, ele gerará o seguinte erro. Corrigi minha resposta para refletir isso.

Msg 4405, Level 16, State 1, Line 1

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

jveazey
fonte
1
Enquanto não é possível atualizar um objeto View que afetará várias tabelas, você pode criar VEZ DE gatilhos que quebram o original em declarações separadas (que afetam uma tabela cada):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.
04:00
9

Isso funciona para o MySQL e é realmente apenas uma transação implícita, mas deve ser algo como isto:

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'

se você estiver fazendo atualizações em várias tabelas que exigem várias instruções ... o que provavelmente é possível se você atualizar uma, e outra com base em outras condições ... você deve usar uma transação. 

user3662407
fonte
1
Este anser ainda é relevante para outros usuários.
Kyselejsyreček
1
@ Kyselejsyreček esta resposta deve ser evitada a todo custo. O MySQL tem peculiaridades e cheiros suficientes, a maioria dos quais na verdade não é suportada, mas é mantida para evitar a quebra de código que depende dessas peculiaridades. A atualização pode facilmente quebrar-los ou resultar em problemas de comportamento e desempenho inesperados
Panagiotis Kanavos
7

Você deve colocar duas instruções de atualização dentro de uma transação

Mick
fonte
2

Você pode escrever uma instrução de atualização para uma tabela e, em seguida, um acionador na primeira atualização da tabela , que atualiza a segunda tabela

Sandip - Desenvolvedor Full Stack
fonte
0

Da minha perspectiva, você pode fazer isso, é uma atualização individual de duas tabelas no 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
Ricardo Roa
fonte
-2

É tão simples quanto esta consulta mostrada abaixo.

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