Как обновить две таблицы в одном операторе в SQL Server 2005?


193

Я хочу обновить две таблицы за один раз. Как мне это сделать в 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
Было бы полезно, если бы вы объяснили почему.
Эрик Миккельсен

2
Боюсь, SQL Server 2005 не поддерживает обновление нескольких таблиц в одном запросе.
Пранав Сингх

Ответы:


195

Вы не можете обновить несколько таблиц в одном операторе, однако вы можете использовать транзакцию, чтобы убедиться, что два UPDATEоператора обрабатываются атомарно. Вы также можете пакетировать их, чтобы избежать поездки в оба конца.

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;

На самом деле, я обновляю записи этих двух таблиц из другой соблазнительной. У temptable есть ссылка на table1, но не на table2. Как я могу обновить ту же запись таблицы 2? Как я буду связывать это?
Джанго

@unknown: на основании вашего комментария вам нужно будет объединить и Table1, и Table2 при обновлении Table2, если вашему запросу на обновление нужны ключи из третьей таблицы. Независимо от этого, вам все равно нужно сделать два отдельных обновления.
Л.Бушкин

3
вероятно, не связано: это не будет работать на MYSQL, потому что синтаксис обновления для MySQL отличается. вам нужно будет ОБНОВИТЬ Table1, Table2 SET Table1.LastName = 'DR. XXXXXX 'ГДЕ T1.id = T2.id
Хуан Вилар

нужно ли нам поддерживать связь между первичным ключом и внешним ключом
srinivas gowda

2
Вы также должны поместить свои операторы обновления в блок try / catch, чтобы избежать частичного обновления в случае ошибки. см. этот вопрос: stackoverflow.com/questions/1749719/…
мехатронер

84

Вы не можете обновить две таблицы одновременно, но вы можете связать обновление с использованием вставки OUTPUT INTO, и вы можете использовать эти выходные данные как объединение для второго обновления:

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;

Я изменил WHEREусловие вашего примера на другое поле, отличное от id. Если это idвам не нужно OUTPUT, вы можете просто UPDATEвторой стол для того же id='010008'.


Это лучший ответ и должен быть признан верным ответом на исходный вопрос. Спасибо. Это сработало для меня.
Fandango68

1
Это T1.fieldдолжно быть Table1.field?
WAF

22

Извините, афаик, вы не можете этого сделать. Чтобы обновить атрибуты в двух разных таблицах, вам необходимо выполнить два отдельных оператора. Но они могут быть в пакетном режиме (набор SQL отправляется на сервер в один прием)


2
Гоша! Я должен использовать слово «Извините» чаще для дополнительных похвал: P
Fandango68

14

Краткий ответ на этот вопрос - нет. Хотя вы можете ввести несколько таблиц в fromпредложении оператора обновления, вы можете указать только одну таблицу после updateключевого слова. Даже если вы напишете «обновляемое» представление (которое является просто представлением, которое следует определенным ограничениям), обновления, подобные этому, завершатся неудачно. Вот соответствующие клипы из документации MSDN (акцент мой).

ОБНОВЛЕНИЕ (Transact-SQL)

Представление, на которое ссылается table_or_view_name, должно быть обновляемым и ссылаться только на одну базовую таблицу в предложении FROM представления. Для получения дополнительной информации об обновляемых представлениях см. CREATE VIEW (Transact-SQL).

СОЗДАТЬ ВИД (Transact-SQL)

Вы можете изменить данные базовой базовой таблицы через представление, если выполняются следующие условия:

  • Любые модификации, включая операторы UPDATE, INSERT и DELETE, должны ссылаться на столбцы только из одной базовой таблицы .
  • Столбцы, изменяемые в представлении, должны напрямую ссылаться на базовые данные в столбцах таблицы. Столбцы не могут быть получены любым другим способом, например, с помощью следующего:
    • Агрегирующая функция: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR и VARP.
    • Вычисление. Столбец не может быть вычислен из выражения, которое использует другие столбцы. Столбцы, которые сформированы с использованием операторов множеств UNION, UNION ALL, CROSSJOIN, EXCEPT и INTERSECT, представляют собой вычисление и также не могут быть обновлены.
  • Изменяемые столбцы не зависят от предложений GROUP BY, HAVING или DISTINCT.
  • TOP не используется нигде в select_statement представления вместе с предложением WITH CHECK OPTION.

Честно говоря, однако, вы должны рассмотреть возможность использования двух разных операторов SQL в транзакции, как показано в примере Л.Бушкина.

ОБНОВЛЕНИЕ: мое первоначальное утверждение, что вы можете обновить несколько таблиц в обновляемом представлении, было неверным. На SQL Server 2005 и 2012 он выдаст следующую ошибку. Я исправил свой ответ, чтобы отразить это.

Msg 4405, Level 16, State 1, Line 1

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


1
Хотя невозможно обновить объект View, который будет влиять на несколько таблиц, вы можете создать триггеры INSTEAD OF, которые разбивают оригинал на отдельные операторы (влияющие на одну таблицу каждый):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

Это работает для MySQL и на самом деле просто неявная транзакция, но она должна выглядеть примерно так:

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'

если вы делаете обновления для нескольких таблиц, которые требуют нескольких операторов ... что, вероятно, возможно, если вы обновляете одну, а затем другую на основе других условий ... вам следует использовать транзакцию. 


1
Этот ансер по-прежнему актуален для других пользователей.
Kyselejsyreček

1
@ Kyselejsyreček этот ответ следует избегать любой ценой. В MySQL достаточно причуд и запахов, большинство из которых на самом деле не поддерживаются, но сохраняются, чтобы избежать взлома кода, который зависит от этих причуд. Обновление может легко сломать их или привести к неожиданным проблемам с поведением и производительностью
Panagiotis Kanavos

7

Вы должны поместить два оператора обновления в транзакцию


2

Вы можете написать оператор обновления для одной таблицы, а затем триггер при обновлении первой таблицы , который обновит вторую таблицу


0

С моей точки зрения, вы можете сделать это, одно-одно обновление двух таблиц в 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

Это так же просто, как этот запрос, показанный ниже.

UPDATE 
  Table1 T1 join Table2 T2 on T1.id = T2.id
SET 
  T1.LastName='DR. XXXXXX', 
  T2.WAprrs='start,stop'
WHERE 
  T1.id = '010008'
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.