Come aggiornare due tabelle in un'istruzione in SQL Server 2005?


193

Voglio aggiornare due tabelle in una volta sola. Come posso farlo in 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
Sarebbe utile se spiegassi il perché.
Eric Mickelsen,

2
Temo che SQL Server 2005 non supporti l'aggiornamento di più tabelle in una query.
Pranav Singh,

Risposte:


195

Non è possibile aggiornare più tabelle in un'unica istruzione, tuttavia è possibile utilizzare una transazione per assicurarsi che due UPDATEistruzioni vengano trattate atomicamente. Puoi anche raggrupparli per evitare un round trip.

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;

In realtà, sto aggiornando i record di queste due tabelle da un altro tentatore. temptable ha un collegamento a table1 ma non a table2. Come posso aggiornare lo stesso record di Table2? Come lo collegherò?
Jango,

@unknown: in base al tuo commento, dovrai unirti a Table1 e Table2 quando aggiorni Table2 se la tua query di aggiornamento richiede le chiavi di una terza tabella. Indipendentemente da ciò, è ancora necessario eseguire due aggiornamenti separati.
LBushkin,

3
probabilmente non correlato: questo non funzionerà su MYSQL perché la sintassi di aggiornamento per mysql è diversa. dovresti andare UPDATE Table1, Table2 SET Table1.LastName = 'DR. XXXXXX 'DOVE T1.id = T2.id
Juan Vilar,

dobbiamo mantenere una relazione tra chiave primaria e chiave esterna tra loro
srinivas gowda,

2
Dovresti anche inserire le tue istruzioni di aggiornamento all'interno del blocco try / catch per evitare aggiornamenti parziali in caso di errore. vedi questa domanda: stackoverflow.com/questions/1749719/…
mechatroner

84

Non è possibile aggiornare due tabelle contemporaneamente, ma è possibile collegare un aggiornamento in un inserto utilizzando OUTPUT INTOe utilizzare questo output come join per il secondo aggiornamento:

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;

Ho cambiato la tua WHEREcondizione di esempio in un campo diverso da id. Se è idil che non ti serve questa fantasia OUTPUT, puoi solo UPDATEil secondo tavolo per lo stesso id='010008'.


Questa è la risposta migliore e dovrebbe essere votata come la vera risposta alla domanda originale. Grazie. Ha funzionato per me.
Fandango68,

1
È che T1.fielddoveva essere Table1.field?
WAF,

22

Spiacente, afaik, non puoi farlo. Per aggiornare gli attributi in due diverse tabelle, è necessario eseguire due istruzioni separate. Ma possono essere in un batch (un set di SQL inviato al server in un round trip)


2
Perbacco! Dovrei usare la parola Mi spiace più spesso per complimenti extra: P
Fandango68

14

La risposta breve è no. Sebbene sia possibile inserire più tabelle nella fromclausola di un'istruzione di aggiornamento, è possibile specificare una sola tabella dopo la updateparola chiave. Anche se si scrive una vista "aggiornabile" (che è semplicemente una vista che segue determinate restrizioni), aggiornamenti come questo falliranno. Ecco le clip pertinenti della documentazione MSDN (l'enfasi è mia).

AGGIORNAMENTO (Transact-SQL)

La vista a cui fa riferimento table_or_view_name deve essere aggiornabile e fare riferimento esattamente a una tabella di base nella clausola FROM della vista. Per ulteriori informazioni sulle viste aggiornabili, vedere CREATE VIEW (Transact-SQL).

CREATE VIEW (Transact-SQL)

È possibile modificare i dati di una tabella di base sottostante tramite una vista, purché siano vere le seguenti condizioni:

  • Qualsiasi modifica, comprese le istruzioni UPDATE, INSERT e DELETE, deve fare riferimento a colonne da una sola tabella di base .
  • Le colonne che vengono modificate nella vista devono fare direttamente riferimento ai dati sottostanti nelle colonne della tabella. Le colonne non possono essere derivate in nessun altro modo, ad esempio attraverso:
    • Una funzione aggregata: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR e VARP.
    • Un calcolo. La colonna non può essere calcolata da un'espressione che utilizza altre colonne. Le colonne formate utilizzando gli operatori dell'insieme UNION, UNION ALL, CROSSJOIN, EXCEPT e INTERSECT equivalgono a un calcolo e inoltre non sono aggiornabili.
  • Le colonne che vengono modificate non sono interessate dalle clausole GROUP BY, HAVING o DISTINCT.
  • TOP non viene utilizzato in nessun punto del select_statement della vista insieme alla clausola WITH CHECK OPTION.

In tutta onestà, tuttavia, dovresti considerare l'utilizzo di due diverse istruzioni SQL all'interno di una transazione come nell'esempio di LBushkin.

AGGIORNAMENTO: la mia affermazione originale secondo cui è possibile aggiornare più tabelle in una vista aggiornabile era errata. Su SQL Server 2005 e 2012, genererà il seguente errore. Ho corretto la mia risposta per riflettere questo.

Msg 4405, Level 16, State 1, Line 1

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


1
Sebbene non sia possibile aggiornare un oggetto View che influirà su più tabelle, è possibile creare trigger INSTEAD OF che suddividono l'originale in istruzioni separate (che incidono su una tabella ciascuna):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.
4:00

9

Questo funziona per MySQL ed è davvero solo una transazione implicita, ma dovrebbe andare qualcosa del genere:

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 stai effettuando aggiornamenti su più tabelle che richiedono più istruzioni ... il che è probabilmente possibile se ne aggiorni uno, quindi un altro in base ad altre condizioni ... dovresti utilizzare una transazione. 


1
Questa risposta è ancora rilevante per gli altri utenti.
Kyselejsyreček,

1
@ Kyselejsyreček questa risposta dovrebbe essere evitata a tutti i costi. MySQL ha abbastanza stranezze e odori, molti dei quali in realtà non sono supportati ma conservati per evitare di rompere il codice che dipende da tali stranezze. L'aggiornamento può facilmente interromperli o causare comportamenti imprevisti e problemi di prestazioni
Panagiotis Kanavos,

7

È necessario inserire due istruzioni di aggiornamento all'interno di una transazione


2

È possibile scrivere un'istruzione di aggiornamento per una tabella e quindi un trigger al primo aggiornamento della tabella che aggiorna la seconda tabella


0

Dal mio punto di vista puoi farlo, il suo aggiornamento uno a uno di due tabelle in 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

-2

È semplice come questa query mostrata di seguito.

UPDATE 
  Table1 T1 join Table2 T2 on T1.id = T2.id
SET 
  T1.LastName='DR. XXXXXX', 
  T2.WAprrs='start,stop'
WHERE 
  T1.id = '010008'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.