Comment mettre à jour deux tables en une seule instruction dans SQL Server 2005?

193

Je veux mettre à jour deux tables en une seule fois. Comment faire cela dans 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
la source
4
Il serait utile que vous expliquiez pourquoi.
Eric Mickelsen
2
J'ai peur, SQL Server 2005 ne prend pas en charge la mise à jour de plusieurs tables dans une seule requête.
Pranav Singh

Réponses:

194

Vous ne pouvez pas mettre à jour plusieurs tables dans une seule instruction, cependant, vous pouvez utiliser une transaction pour vous assurer que deux UPDATEinstructions sont traitées atomiquement. Vous pouvez également les regrouper pour éviter un aller-retour.

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
la source
En fait, je mets à jour les enregistrements de ces deux tables à partir d'une autre tentation. tentable a un lien vers table1 mais pas table2. Comment puis-je mettre à jour le même enregistrement de Table2? Comment vais-je le lier?
Jango
@unknown: sur la base de votre commentaire, vous devrez vous joindre à la fois à Table1 et Table2 lorsque vous mettez à jour Table2 si votre requête de mise à jour a besoin des clés d'une troisième table. Quoi qu'il en soit, vous devez toujours effectuer deux mises à jour distinctes.
LBushkin
3
probablement pas lié: cela ne fonctionnera pas sur MYSQL car la syntaxe de mise à jour pour mysql est différente. vous devez aller à UPDATE Table1, Table2 SET Table1.LastName = 'DR. XXXXXX 'OERE T1.id = T2.id
Juan Vilar
avons-nous besoin de maintenir une relation entre la clé primaire et la clé étrangère
srinivas gowda
2
Vous devez également placer vos instructions de mise à jour dans le bloc try / catch pour éviter une mise à jour partielle en cas d'erreur. voir cette question: stackoverflow.com/questions/1749719/…
mechatroner
84

Vous ne pouvez pas mettre à jour deux tables à la fois, mais vous pouvez lier une mise à jour dans un insert à l'aide de OUTPUT INTO, et vous pouvez utiliser cette sortie comme jointure pour la deuxième mise à jour:

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;

J'ai changé votre WHEREcondition d' exemple pour un autre champ que id. Si idvous n'avez pas besoin de cette fantaisie OUTPUT, vous pouvez simplement utiliser UPDATEla deuxième table pour la même chose id='010008'.

Remus Rusanu
la source
C'est la meilleure réponse et devrait être votée comme la vraie réponse à la question d'origine. Je vous remercie. Ça a marché pour moi.
Fandango68
1
Est-ce T1.fieldcensé l'être Table1.field?
WAF du
22

Désolé, afaik, vous ne pouvez pas faire ça. Pour mettre à jour les attributs dans deux tables différentes, vous devrez exécuter deux instructions distinctes. Mais ils peuvent être dans un lot (un ensemble de SQL envoyé au serveur en un aller-retour)

Charles Bretana
la source
2
Ça alors! Je devrais utiliser le mot Désolé plus souvent pour des félicitations supplémentaires: P
Fandango68
14

La réponse courte est non. Bien que vous puissiez saisir plusieurs tableaux dans lefrom clause d'une instruction de mise à jour, vous ne pouvez spécifier qu'une seule table après le updatemot clé. Même si vous écrivez une vue "modifiable" (qui est simplement une vue qui suit certaines restrictions), les mises à jour comme celle-ci échoueront. Voici les extraits pertinents de la documentation MSDN (c'est moi qui souligne).

MISE À JOUR (Transact-SQL)

La vue référencée par table_or_view_name doit pouvoir être mise à jour et référencer exactement une table de base dans la clause FROM de la vue. Pour plus d'informations sur les vues pouvant être mises à jour, consultez CREATE VIEW (Transact-SQL).

CRÉER UNE VUE (Transact-SQL)

Vous pouvez modifier les données d'une table de base sous-jacente via une vue, tant que les conditions suivantes sont remplies:

  • Toutes les modifications, y compris les instructions UPDATE, INSERT et DELETE, doivent référencer les colonnes d' une seule table de base .
  • Les colonnes en cours de modification dans la vue doivent référencer directement les données sous-jacentes dans les colonnes du tableau. Les colonnes ne peuvent pas être dérivées d'une autre manière, par exemple par le biais des éléments suivants:
    • Une fonction d'agrégation: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR et VARP.
    • Un calcul. La colonne ne peut pas être calculée à partir d'une expression qui utilise d'autres colonnes. Les colonnes qui sont formées à l'aide des opérateurs d'ensemble UNION, UNION ALL, CROSSJOIN, EXCEPT et INTERSECT équivalent à un calcul et ne peuvent pas non plus être mises à jour.
  • Les colonnes en cours de modification ne sont pas affectées par les clauses GROUP BY, HAVING ou DISTINCT.
  • TOP n'est utilisé nulle part dans l'instruction select_statement de la vue avec la clause WITH CHECK OPTION.

En toute honnêteté, cependant, vous devriez envisager d'utiliser deux instructions SQL différentes dans une transaction, selon l'exemple de LBushkin.

MISE À JOUR: Mon affirmation originale selon laquelle vous pouviez mettre à jour plusieurs tables dans une vue pouvant être mise à jour était fausse. Sur SQL Server 2005 et 2012, il générera l'erreur suivante. J'ai corrigé ma réponse pour refléter cela.

Msg 4405, Level 16, State 1, Line 1

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

jveazey
la source
1
Bien qu'il ne soit pas possible de mettre à jour un objet View qui affectera plusieurs tables, vous pouvez créer des déclencheurs INSTEAD OF qui décomposent l'original en instructions distinctes (affectant une table chacune):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.
4AM
9

Cela fonctionne pour MySQL et n'est vraiment qu'une transaction implicite, mais cela devrait ressembler à ceci:

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'

si vous effectuez des mises à jour de plusieurs tables qui nécessitent plusieurs instructions… ce qui est probablement possible si vous en mettez à jour une, puis une autre en fonction d'autres conditions… vous devez utiliser une transaction. 

user3662407
la source
1
Cet anser est toujours pertinent pour les autres utilisateurs.
Kyselejsyreček
1
@ Kyselejsyreček cette réponse doit être évitée à tout prix. MySQL a suffisamment de bizarreries et d'odeurs, dont la plupart ne sont en fait pas prises en charge mais conservées pour éviter de casser le code qui dépend de ces bizarreries. La mise à niveau peut facilement les briser ou entraîner des problèmes de comportement et de performances inattendus
Panagiotis Kanavos
7

Vous devez placer deux instructions de mise à jour dans une transaction

Mick
la source
2

Vous pouvez écrire une instruction de mise à jour pour une table , puis un déclencheur lors de la première mise à jour de la table , qui met à jour la deuxième table

Sandip - Développeur Full Stack
la source
0

De mon point de vue, vous pouvez le faire, sa mise à jour une à une de deux tables dans 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
la source
-2

C'est aussi simple que cette requête ci-dessous.

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
la source