Jak zaktualizować dwie tabele w jednej instrukcji w SQL Server 2005?

193

Chcę zaktualizować dwie tabele za jednym razem. Jak to zrobić w 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
źródło
4
Byłoby pomocne, gdybyś wyjaśnił dlaczego.
Eric Mickelsen,
2
Obawiam się, że SQL Server 2005 nie obsługuje aktualizacji wielu tabel w jednym zapytaniu.
Pranav Singh

Odpowiedzi:

194

Nie można aktualizować wielu tabel w jednej instrukcji, można jednak użyć transakcji, aby upewnić się, że dwie UPDATEinstrukcje są traktowane atomowo. Możesz je również grupować, aby uniknąć podróży w obie strony.

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
źródło
W rzeczywistości aktualizuję rekordy tych dwóch tabel z innego kuszącego. temptable ma link do tabeli 1, ale nie tabeli 2. Jak mogę zaktualizować ten sam rekord tabeli 2? Jak mogę to połączyć?
Jango,
@unknown: W oparciu o Twój komentarz, musisz zaktualizować tabelę 1 i tabelę 2 podczas aktualizacji tabeli 2, jeśli zapytanie o aktualizację wymaga kluczy z trzeciej tabeli. Niezależnie od tego nadal musisz wykonać dwie osobne aktualizacje.
LBushkin
3
prawdopodobnie niezwiązane: nie będzie działać na MYSQL, ponieważ składnia aktualizacji mysql jest inna. musisz przejść na UPDATE Table1, Table2 SET Table1.LastName = 'DR. XXXXXX 'GDZIE T1.id = T2.id
Juan Vilar,
czy musimy utrzymywać między nimi klucz główny i klucz obcy
srinivas gowda
2
Powinieneś także umieścić swoje instrukcje aktualizacji w bloku try / catch, aby uniknąć częściowej aktualizacji w przypadku błędu. zobacz to pytanie: stackoverflow.com/questions/1749719/…
mechatroner
84

Nie można zaktualizować dwóch tabel jednocześnie, ale można połączyć aktualizację ze wstawką za pomocą OUTPUT INTOi można użyć tego wyniku jako połączenia dla drugiej aktualizacji:

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;

Zmieniłem twój przykładowy WHEREwarunek na inny niż id. Jeśli to nie jest idci potrzebne OUTPUT, możesz po prostu UPDATEdrugi stół dla tego samego id='010008'.

Remus Rusanu
źródło
To najlepsza odpowiedź i powinna zostać uznana za prawdziwą odpowiedź na pierwotne pytanie. Dziękuję Ci. To zadziałało dla mnie.
Fandango68,
1
Czy tak T1.fieldma być Table1.field?
WAF
22

Przepraszamy, nie możesz tego zrobić. Aby zaktualizować atrybuty w dwóch różnych tabelach, musisz wykonać dwie osobne instrukcje. Ale mogą być partiami (zestaw SQL wysłany do serwera podczas jednej podróży w obie strony)

Charles Bretana
źródło
2
Boże! Powinienem częściej używać słowa Przepraszam, aby wyrazić swoje dodatkowe uznanie: P
Fandango68,
14

Krótka odpowiedź na to pytanie brzmi: nie. Chociaż w fromklauzuli instrukcji aktualizacji można wprowadzić wiele tabel , można podać tylko jedną tabelę po updatesłowie kluczowym. Nawet jeśli napiszesz „aktualizowalny” widok (który jest po prostu widokiem zgodnym z pewnymi ograniczeniami), takie aktualizacje nie powiodą się. Oto odpowiednie klipy z dokumentacji MSDN (nacisk należy do mnie).

AKTUALIZACJA (Transact-SQL)

Widok przywoływany przez table_or_view_name musi być aktualizowalny i odwoływać się dokładnie do jednej tabeli bazowej w klauzuli FROM widoku. Aby uzyskać więcej informacji o aktualizowalnych widokach, zobacz UTWÓRZ WIDOK (Transact-SQL).

UTWÓRZ WIDOK (Transact-SQL)

Możesz modyfikować dane podstawowej tabeli bazowej poprzez widok, o ile spełnione są następujące warunki:

  • Wszelkie modyfikacje, w tym instrukcje UPDATE, INSERT i DELETE, muszą odwoływać się do kolumn tylko z jednej tabeli podstawowej .
  • Zmodyfikowane kolumny w widoku muszą bezpośrednio odwoływać się do podstawowych danych w kolumnach tabeli. Kolumn nie można wyprowadzić w żaden inny sposób, na przykład przez:
    • Funkcja agregująca: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR i VARP.
    • Obliczenia. Kolumny nie można obliczyć z wyrażenia korzystającego z innych kolumn. Kolumny utworzone przy użyciu operatorów zestawów UNION, UNION ALL, CROSSJOIN, EXCEPT i INTERSECT są obliczane i nie można ich aktualizować.
  • Na modyfikowane kolumny nie mają wpływu klauzule GROUP BY, HAVING lub DISTINCT.
  • TOP nie jest nigdzie używany w select_statement widoku wraz z klauzulą ​​WITH CHECK OPTION.

Szczerze mówiąc, powinieneś rozważyć użycie dwóch różnych instrukcji SQL w ramach transakcji, tak jak w przykładzie LBushkina.

AKTUALIZACJA: Moje pierwotne twierdzenie, że można aktualizować wiele tabel w widoku, który można aktualizować, było błędne. W SQL Server 2005 i 2012 wygeneruje następujący błąd. Poprawiłem swoją odpowiedź, aby to odzwierciedlić.

Msg 4405, Level 16, State 1, Line 1

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

Jveazey
źródło
1
Chociaż nie można zaktualizować obiektu View, który wpłynie na wiele tabel, można utworzyć wyzwalacze INSTEAD OF, które dzielą oryginał na osobne instrukcje (wpływające na jedną tabelę):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

Działa to dla MySQL i jest tak naprawdę tylko niejawną transakcją, ale powinno wyglądać mniej więcej tak:

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'

jeśli wykonujesz aktualizacje wielu tabel, które wymagają wielu wyciągów… co jest możliwe, jeśli zaktualizujesz jeden, a następnie inny na podstawie innych warunków… powinieneś skorzystać z transakcji. 

użytkownik3662407
źródło
1
Ten anser jest nadal odpowiedni dla innych użytkowników.
Kyselejsyreček
1
@ Kyselejsyreček tej odpowiedzi należy unikać za wszelką cenę. MySQL ma dość dziwactw i zapachów, z których większość nie jest obsługiwana, ale zachowana, aby uniknąć łamania kodu zależnego od tych dziwactw. Aktualizacja może łatwo je zepsuć lub spowodować nieoczekiwane problemy z zachowaniem i wydajnością
Panagiotis Kanavos
7

W transakcji należy umieścić dwie instrukcje aktualizacji

Mick
źródło
2

Możesz napisać instrukcję aktualizacji dla jednej tabeli, a następnie wyzwalacz przy pierwszej aktualizacji tabeli , która aktualizuje drugą tabelę

Sandip - programista z pełnym stosem
źródło
0

Z mojego punktu widzenia możesz to zrobić, to jedna do jednej aktualizacja dwóch tabel w 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
źródło
-2

Jest to tak proste, jak to zapytanie pokazane poniżej.

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
źródło