¿Cómo actualizar dos tablas en una declaración en SQL Server 2005?

193

Quiero actualizar dos tablas de una vez. ¿Cómo hago eso en 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
fuente
44
Sería útil si explicaras por qué.
Eric Mickelsen
2
Me temo que SQL Server 2005 no admite la actualización de varias tablas en una consulta.
Pranav Singh

Respuestas:

194

No puede actualizar varias tablas en una declaración, sin embargo, puede usar una transacción para asegurarse de que dos UPDATEdeclaraciones sean tratadas atómicamente. También puede agruparlos para evitar un viaje de ida y vuelta.

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
fuente
En realidad, estoy actualizando los registros de estas dos tablas desde otro tentador. temptable tiene un enlace a la tabla1 pero no a la tabla2. ¿Cómo puedo actualizar el mismo registro de Table2? ¿Cómo lo vincularé?
Jango
@unknown: según su comentario, necesitaría unirse a Table1 y Table2 cuando actualice Table2 si su consulta de actualización necesita las claves de una tercera tabla. Independientemente de eso, aún necesita hacer dos actualizaciones separadas.
LBushkin
3
probablemente no esté relacionado: esto no funcionará en MYSQL porque la sintaxis de actualización para mysql es diferente. tendrías que ACTUALIZAR Table1, Table2 SET Table1.LastName = 'DR. XXXXXX 'WHERE T1.id = T2.id
Juan Vilar
¿Necesitamos mantener la relación de clave primaria y clave externa entre ellos
srinivas gowda
2
También debe colocar sus declaraciones de actualización dentro del bloque try / catch para evitar una actualización parcial en caso de error. vea esta pregunta: stackoverflow.com/questions/1749719/…
mechatroner
84

No puede actualizar dos tablas a la vez, pero puede vincular una actualización a una inserción usando OUTPUT INTO, y puede usar esta salida como una combinación para la segunda actualización:

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;

Cambié su WHEREcondición de ejemplo para que sea otro campo que no sea id. Si es idque no necesita esta fantasía OUTPUT, puede simplemente UPDATEla segunda tabla para lo mismo id='010008'.

Remus Rusanu
fuente
Esta es la mejor respuesta y debe votarse como la verdadera respuesta a la pregunta original. Gracias. Funcionó para mi.
Fandango68
1
¿Se T1.fieldsupone que es eso Table1.field?
WAF
22

Lo siento, afaik, no puedes hacer eso. Para actualizar los atributos en dos tablas diferentes, deberá ejecutar dos declaraciones separadas. Pero pueden estar en un lote (un conjunto de SQL enviado al servidor en un solo viaje de ida y vuelta)

Charles Bretana
fuente
2
¡Dios mio! Debería usar la palabra Perdón más a menudo para felicitaciones adicionales: P
Fandango68
14

La respuesta corta a eso es no. Si bien puede ingresar varias tablas en la fromcláusula de una declaración de actualización, solo puede especificar una sola tabla después de la updatepalabra clave. Incluso si escribe una vista "actualizable" (que es simplemente una vista que sigue ciertas restricciones), las actualizaciones como esta fallarán. Aquí están los clips relevantes de la documentación de MSDN (el énfasis es mío).

ACTUALIZACIÓN (Transact-SQL)

La vista a la que hace referencia table_or_view_name debe ser actualizable y hacer referencia exactamente a una tabla base en la cláusula FROM de la vista. Para obtener más información sobre vistas actualizables, vea CREATE VIEW (Transact-SQL).

CREAR VISTA (Transact-SQL)

Puede modificar los datos de una tabla base subyacente a través de una vista, siempre que se cumplan las siguientes condiciones:

  • Cualquier modificación, incluidas las declaraciones UPDATE, INSERT y DELETE, debe hacer referencia a columnas de una sola tabla base .
  • Las columnas que se modifican en la vista deben hacer referencia directamente a los datos subyacentes en las columnas de la tabla. Las columnas no se pueden derivar de ninguna otra manera, como a través de lo siguiente:
    • Una función agregada: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR y VARP.
    • Un cómputo La columna no se puede calcular a partir de una expresión que usa otras columnas. Las columnas que se forman utilizando los operadores de conjunto UNION, UNION ALL, CROSSJOIN, EXCEPT e INTERSECT equivalen a un cálculo y tampoco son actualizables.
  • Las columnas que se modifican no se ven afectadas por las cláusulas GROUP BY, HAVING o DISTINCT.
  • TOP no se utiliza en ningún lugar de la selección select_statement de la vista junto con la cláusula WITH CHECK OPTION.

Sin embargo, con toda honestidad, debe considerar usar dos declaraciones SQL diferentes dentro de una transacción según el ejemplo de LBushkin.

ACTUALIZACIÓN: Mi afirmación original de que podía actualizar varias tablas en una vista actualizable era incorrecta. En SQL Server 2005 y 2012, generará el siguiente error. He corregido mi respuesta para reflejar esto.

Msg 4405, Level 16, State 1, Line 1

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

jveazey
fuente
1
Si bien no es posible actualizar un objeto View que afectará a varias tablas, puede crear disparadores INSTEAD OF que dividen el original en declaraciones separadas (que afectan a una tabla cada una):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

Esto funciona para MySQL y en realidad es solo una transacción implícita, pero debería ser algo como esto:

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 está realizando actualizaciones en varias tablas que requieren múltiples declaraciones ... lo que probablemente sea posible si actualiza una, luego otra en función de otras condiciones ... debe usar una transacción. 

usuario3662407
fuente
1
Esta respuesta sigue siendo relevante para otros usuarios.
Kyselejsyreček
1
@ Kyselejsyreček esta respuesta debe evitarse a toda costa. MySQL tiene suficientes peculiaridades y olores, la mayoría de los cuales en realidad no son compatibles pero se retienen para evitar romper el código que depende de esas peculiaridades. La actualización puede romperlos fácilmente o generar comportamientos inesperados y problemas de rendimiento
Panagiotis Kanavos
7

Debe colocar dos declaraciones de actualización dentro de una transacción

Mick
fuente
2

Puede escribir una declaración de actualización para una tabla y luego un activador en la actualización de la primera tabla , que actualiza la segunda tabla

Sandip - Desarrollador Full Stack
fuente
0

Desde mi perspectiva, puede hacer esto, es una actualización individual de dos tablas en 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
fuente
-2

Es tan simple como esta consulta que se muestra a continuación.

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
fuente