Как мне выполнить ОБНОВЛЕНИЕ из SELECT в SQL Server?

3969

В SQL Server можно вставлять строки в таблицу с помощью INSERT.. SELECTоператора:

INSERT INTO Table (col1, col2, col3)
SELECT col1, col2, col3 
FROM other_table 
WHERE sql = 'cool'

Можно ли также обновить таблицу с помощью SELECT? У меня есть временная таблица, содержащая значения, и я хотел бы обновить другую таблицу, используя эти значения. Возможно что-то вроде этого:

UPDATE Table SET col1, col2
SELECT col1, col2 
FROM other_table 
WHERE sql = 'cool'
WHERE Table.id = other_table.id
2
  • ОБНОВИТЬ Table_A SET Table_A.col1 = Table_B.col1, Table_A.col2 = Table_B.col2 FROM Some_Table AS Table_A INNER JOIN Other_Table AS Table_B ON Table_A.id = Table_B.id WHERE Table_A.col3 = 'cool' 3 августа в 17:04
  • ОБНОВЛЕНИЕ YourTable SET Col1 = OtherTable.Col1, Col2 = OtherTable.Col2 FROM (SELECT ID, Col1, Col2 FROM other_table) AS OtherTable WHERE OtherTable.ID = YourTable.ID 3 августа в 17:04
5715
UPDATE
    Table_A
SET
    Table_A.col1 = Table_B.col1,
    Table_A.col2 = Table_B.col2
FROM
    Some_Table AS Table_A
    INNER JOIN Other_Table AS Table_B
        ON Table_A.id = Table_B.id
WHERE
    Table_A.col3 = 'cool'
8
  • 24
    Если вы редактируете ссылку между таблицами ( SET Table.other_table_id = @NewValue), измените оператор ON на что-то вродеON Table.id = @IdToEdit AND other_table.id = @NewValue
    Trisped
    24 окт.
  • 2
    @CharlesWood да. У меня такой же вопрос в MySQL. Было бы здорово, если бы кто-нибудь знал, как внедрить это в MySQL и поделиться со всеми. Я уверен, что многие люди ищут решение для версии MySQL. 27 ноя '13 в 3:34
  • 1
    Как использовать псевдоним в наборе? обновить набор таблиц a.col1 = b.col2 из таблицы a внутреннее соединение table2 b на a.id = b.id; Вместо этого я должен использовать набор обновленных таблиц table.col1 = b.col2 из таблицы a inner join table2 b на a.id = b.id; 20 янв.
  • 14
    В некоторой степени это связано с тем, что мне часто нравится сначала писать свои запросы UPDATE как операторы SELECT, чтобы я мог видеть данные, которые будут обновлены, прежде чем я выполню. Себастьян описывает эту технику в недавнем сообщении в блоге: sqlity.net/en/2867/update-from-select 21 авг.
  • 1
    Вы не можете сделать SET Table_A.col1 = SUM(Table_B.col1)ни какой другой агрегат. Ответ Джамаля позволяет вам поместить агрегат в SELECT stackoverflow.com/a/8963158/695671
    Jason S
    14 июля '19 в 22: 312019-07-14 22:31
827

В SQL Server 2008 (или новее) используйте MERGE

MERGE INTO YourTable T
   USING other_table S 
      ON T.id = S.id
         AND S.tsql = 'cool'
WHEN MATCHED THEN
   UPDATE 
      SET col1 = S.col1, 
          col2 = S.col2;

Альтернативно:

MERGE INTO YourTable T
   USING (
          SELECT id, col1, col2 
            FROM other_table 
           WHERE tsql = 'cool'
         ) S
      ON T.id = S.id
WHEN MATCHED THEN
   UPDATE 
      SET col1 = S.col1, 
          col2 = S.col2;
10
  • 133
    MERGEтакже может использоваться для «Upserting» записей; то есть, UPDATEесли соответствующая запись существует, INSERTновая запись, если совпадение не найдено 15 мая '12 в 19:51
  • 18
    Для меня это было примерно в 10 раз быстрее, чем эквивалентное выражение update ... join. 3 апр '13 в 2:49
  • 18
    MERGE также можно использовать для УДАЛЕНИЯ. Но будьте осторожны с MERGE, поскольку таблица TARGET не может быть удаленной таблицей.
    Möoz
    08 авг.
  • 25
    Ошибки слияния: mssqltips.com/sqlservertip/3074/…
    Simon D
    27 авг.
  • 17
    @SimonD: выберите любое ключевое слово SQL Server, и вы обнаружите ошибки. Ваша точка зрения? Я держу пари, что есть больше ошибок (и более фундаментальных тоже), связанных с UPDATEчем MERGE, люди только что научились жить с ними, и они стали частью ландшафта («особенности»). Учтите, что блогов не существовало, когда UPDATEбыл новичок в блоке. 03 окт.
753
UPDATE YourTable 
SET Col1 = OtherTable.Col1, 
    Col2 = OtherTable.Col2 
FROM (
    SELECT ID, Col1, Col2 
    FROM other_table) AS OtherTable
WHERE 
    OtherTable.ID = YourTable.ID
4
  • 9
    Безусловно, самый простой! Однако вам не хватает поля идентификатора из внутреннего SELECT. Это понадобится вам для работы предложения WHERE 31 окт.
  • 15
    Это будет работать почти во всех СУБД, что означает: учиться один раз, выполнять везде. Если для вас это важнее, чем производительность, вы можете предпочесть этот ответ, особенно если ваше обновление является разовым, чтобы исправить некоторые данные. 1 фев '16 в 14:46
  • 3
    Если вам нужно настроить первую таблицу с агрегатами из второй, вы можете поместить агрегаты в подзапрос select, что вы не можете сделать SET Table_A.col1 = SUM(Table_B.col1)(или любую другую агрегатную функцию). Так лучше, чем ответ Робина Дэя для этой цели.
    Jason S
    14 июля '19 в 22: 382019-07-14 22:38
  • Мне очень нравится это решение, так как оно кажется естественным дополнением к принципу INSERT ... SELECTработы. Спасибо, что поделился! 6 июня в 17:50
297

Я бы изменил отличный ответ Робина на следующее:

UPDATE Table
SET Table.col1 = other_table.col1,
 Table.col2 = other_table.col2
FROM
    Table
INNER JOIN other_table ON Table.id = other_table.id
WHERE
    Table.col1 != other_table.col1
OR Table.col2 != other_table.col2
OR (
    other_table.col1 IS NOT NULL
    AND Table.col1 IS NULL
)
OR (
    other_table.col2 IS NOT NULL
    AND Table.col2 IS NULL
)

Без предложения WHERE вы повлияете даже на строки, которые не должны быть затронуты, что может (возможно) вызвать перерасчет индекса или сработать триггеры, которые действительно не должны были запускаться.

6
  • 7
    Это предполагает, что ни один из столбцов не допускает значения NULL. 6 нояб.
  • 4
    Вы правы, я набирал пример от руки. Я добавил третье и четвертое предложения к оператору where, чтобы справиться с этим. 11 нояб.
  • 47
    WHERE EXISTS(SELECT T1.Col1, T1.Col2 EXCEPT SELECT T2.Col1, T2.Col2)) более лаконично. 27 мая '12 в 09:44
  • 5
    не должен ли оператор также содержать эти два в предложении where? (other_table.col1 имеет значение NULL, а table.col1 не равно NULL) или (other_table.col2 имеет значение NULL, а table.col2 не равно NULL)
    Barka
    15 мая '13 в 4:03
  • 4
    Зависит от того, хотите ли вы заменить значения NULL в месте назначения значениями NULL из источника. Часто я этого не делаю. Но если вы это сделаете, лучше всего использовать конструкцию Мартина предложения where. 16 мая '13 в 16:35
218

В одну сторону

UPDATE t 
SET t.col1 = o.col1, 
    t.col2 = o.col2
FROM 
    other_table o 
  JOIN 
    t ON t.id = o.id
WHERE 
    o.sql = 'cool'
0
180

Другая возможность, о которой еще не упоминалось, - это просто вставить сам SELECTоператор в CTE, а затем обновить CTE.

;WITH CTE
     AS (SELECT T1.Col1,
                T2.Col1 AS _Col1,
                T1.Col2,
                T2.Col2 AS _Col2
         FROM   T1
                JOIN T2
                  ON T1.id = T2.id
         /*Where clause added to exclude rows that are the same in both tables
           Handles NULL values correctly*/
         WHERE EXISTS(SELECT T1.Col1,
                             T1.Col2
                       EXCEPT
                       SELECT T2.Col1,
                              T2.Col2))
UPDATE CTE
SET    Col1 = _Col1,
       Col2 = _Col2

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

Это также имеет то же ограничение, что и собственный UPDATE ... FROMсинтаксис, показанный в четырех других ответах. Если исходная таблица находится на стороне «многие» соединения «один-ко-многим», то не определено, какая из возможных совпадающих соединенных записей будет использоваться в Update(проблема, которую можно MERGEизбежать, вызвав ошибку при попытке обновить один и тот же ряд более одного раза).

3
  • 3
    есть какое-то значение имени CTE?
    Raptor
    8 окт.
  • 21 год
    @ShivanRaptor - это аббревиатура от Common Table Expression . В данном случае просто произвольный псевдоним. 8 окт.
  • 3
    Это также хорошо работает с несколькими CTE: ;WITH SomeCompexCTE AS (...), CTEAsAbove AS (SELECT T1.Col1,... FROM T1 JOIN SomeComplexCTE...) UPDATE CTEAsAbove SET Col1=_Col1, ... 29 авг.
130

Для записи (и других, ищущих, как я), вы можете сделать это в MySQL следующим образом:

UPDATE first_table, second_table
SET first_table.color = second_table.color
WHERE first_table.id = second_table.foreign_id
0
105

Использование псевдонима:

UPDATE t
   SET t.col1 = o.col1
  FROM table1 AS t
         INNER JOIN 
       table2 AS o 
         ON t.id = o.id
81

Самый простой способ сделать это:

UPDATE
    table_to_update,
    table_info
SET
    table_to_update.col1 = table_info.col1,
    table_to_update.col2 = table_info.col2

WHERE
    table_to_update.ID = table_info.ID
1
  • 22
    Это не синтаксис сервера SQl, и он не будет работать на сервере SQL.
    HLGEM
    24 апр '13 в 18:32
69

Это может быть нишевой причиной для выполнения обновления (например, в основном используется в процедуре) или может быть очевидным для других, но также следует указать, что вы можете выполнить оператор update-select без использования соединения (в случае таблицы, между которыми вы обновляете, не имеют общего поля).

update
    Table
set
    Table.example = a.value
from
    TableExample a
where
    Table.field = *key value* -- finds the row in Table 
    AND a.field = *key value* -- finds the row in TableExample a
64

Вот еще один полезный синтаксис:

UPDATE suppliers
SET supplier_name = (SELECT customers.name
                     FROM customers
                     WHERE customers.customer_id = suppliers.supplier_id)
WHERE EXISTS (SELECT customers.name
              FROM customers
              WHERE customers.customer_id = suppliers.supplier_id);

Он проверяет, является ли он нулевым, используя "WHERE EXIST".

0
59

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

UPDATE Table 
SET  Table.col1 = other_table.col1,
     Table.col2 = other_table.col2 
--select Table.col1, other_table.col,Table.col2,other_table.col2, *   
FROM     Table 
INNER JOIN     other_table 
    ON     Table.id = other_table.id 
0
57

Если вы используете MySQL вместо SQL Server, синтаксис будет следующим:

UPDATE Table1
INNER JOIN Table2
ON Table1.id = Table2.id
SET Table1.col1 = Table2.col1,
    Table1.col2 = Table2.col2
1
  • Что, если мы хотим обновить Table2.col1? как мы это сделаем. таблица два извлекается на основе условия запроса. 26 ноя '20 в 21:03
56

ОБНОВЛЕНИЕ из SELECT с INNER JOIN в базе данных SQL

Поскольку на этот пост слишком много ответов, которые получили наибольшее количество голосов, я подумал, что внесу свое предложение и здесь. Хотя вопрос очень интересный, я видел на многих форумах и сделал решение, используя INNER JOIN со скриншотами.

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

Затем я выполнил команду SELECT, чтобы просмотреть вставленные записи.

Затем я создал новую таблицу с именем schoolnew и аналогичным образом выполнил над ней вышеуказанные действия.

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

Теперь здесь я хочу внести некоторые изменения в третью и четвертую строки, чтобы завершить это действие, я выполняю команду UPDATE с INNER JOIN .

Чтобы просмотреть изменения, я выполняю команду SELECT .

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

0
47

И если вы хотите присоединиться к столу сам с собой (что случается не слишком часто):

update t1                    -- just reference table alias here
set t1.somevalue = t2.somevalue
from table1 t1               -- these rows will be the targets
inner join table1 t2         -- these rows will be used as source
on ..................        -- the join clause is whatever suits you
1
  • 8
    +1, но вы должны были использовать соответствующие псевдонимы, такие как targett1и, sourcet1а не (или а также) комментарии. 30 июня '14 в 2:05
45

Обновление CTEболее читабельно, чем другие ответы здесь:

;WITH cte
     AS (SELECT col1,col2,id
         FROM   other_table
         WHERE  sql = 'cool')
UPDATE A
SET    A.col1 = B.col1,
       A.col2 = B.col2
FROM   table A
       INNER JOIN cte B
               ON A.id = B.id
44

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

UPDATE x
SET    x.col1 = x.newCol1,
       x.col2 = x.newCol2
FROM   (SELECT t.col1,
               t2.col1 AS newCol1,
               t.col2,
               t2.col2 AS newCol2
        FROM   [table] t
               JOIN other_table t2
                 ON t.ID = t2.ID) x
43

Если вы используете SQL Server, вы можете обновить одну таблицу из другой без указания соединения и просто связать две из whereпредложения. Это значительно упрощает SQL-запрос:

UPDATE Table1
SET Table1.col1 = Table2.col1,
    Table1.col2 = Table2.col2
FROM
    Table2
WHERE
    Table1.id = Table2.id
0
29

Здесь объединены все различные подходы.

  1. Выберите обновление
  2. Обновление с общим табличным выражением
  3. Объединить

Ниже приведен образец структуры таблицы, которая будет обновляться с Product_BAK до таблицы Product.

Продукт

CREATE TABLE [dbo].[Product](
    [Id] [int] IDENTITY(1, 1) NOT NULL,
    [Name] [nvarchar](100) NOT NULL,
    [Description] [nvarchar](100) NULL
) ON [PRIMARY]

Product_BIN

    CREATE TABLE [dbo].[Product_BAK](
        [Id] [int] IDENTITY(1, 1) NOT NULL,
        [Name] [nvarchar](100) NOT NULL,
        [Description] [nvarchar](100) NULL
    ) ON [PRIMARY]

1. Выберите обновление.

    update P1
    set Name = P2.Name
    from Product P1
    inner join Product_Bak P2 on p1.id = P2.id
    where p1.id = 2

2. Обновите общее табличное выражение

    ; With CTE as
    (
        select id, name from Product_Bak where id = 2
    )
    update P
    set Name = P2.name
    from  product P  inner join CTE P2 on P.id = P2.id
    where P2.id = 2

3. Объединить

    Merge into product P1
    using Product_Bak P2 on P1.id = P2.id

    when matched then
    update set p1.[description] = p2.[description], p1.name = P2.Name;

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

    Merge into product P1
    using Product_Bak P2 on P1.id = P2.id;

    when matched then
    update set p1.[description] = p2.[description], p1.name = P2.Name;

    WHEN NOT MATCHED THEN
    insert (name, description)
    values(p2.name, P2.description);
25

Другой способ - использовать производную таблицу:

UPDATE t
SET t.col1 = a.col1
    ,t.col2 = a.col2
FROM (
SELECT id, col1, col2 FROM @tbl2) a
INNER JOIN @tbl1 t ON t.id = a.id

Образец данных

DECLARE @tbl1 TABLE (id INT, col1 VARCHAR(10), col2 VARCHAR(10))
DECLARE @tbl2 TABLE (id INT, col1 VARCHAR(10), col2 VARCHAR(10))

INSERT @tbl1 SELECT 1, 'a', 'b' UNION SELECT 2, 'b', 'c'

INSERT @tbl2 SELECT 1, '1', '2' UNION SELECT 2, '3', '4'

UPDATE t
SET t.col1 = a.col1
    ,t.col2 = a.col2
FROM (
SELECT id, col1, col2 FROM @tbl2) a
INNER JOIN @tbl1 t ON t.id = a.id

SELECT * FROM @tbl1
SELECT * FROM @tbl2
25
UPDATE TQ
SET TQ.IsProcessed = 1, TQ.TextName = 'bla bla bla'
FROM TableQueue TQ
INNER JOIN TableComment TC ON TC.ID = TQ.TCID
WHERE TQ.IsProcessed = 0

Чтобы убедиться, что вы обновляете то, что хотите, выберите сначала

SELECT TQ.IsProcessed, 1 AS NewValue1, TQ.TextName, 'bla bla bla' AS NewValue2
FROM TableQueue TQ
INNER JOIN TableComment TC ON TC.ID = TQ.TCID
WHERE TQ.IsProcessed = 0
24

Есть даже более короткий метод, который может вас удивить:

Пример набора данных:

CREATE TABLE #SOURCE ([ID] INT, [Desc] VARCHAR(10));
CREATE TABLE #DEST   ([ID] INT, [Desc] VARCHAR(10));

INSERT INTO #SOURCE VALUES(1,'Desc_1'), (2, 'Desc_2'), (3, 'Desc_3');
INSERT INTO #DEST   VALUES(1,'Desc_4'), (2, 'Desc_5'), (3, 'Desc_6');

Код:

UPDATE #DEST
SET #DEST.[Desc] = #SOURCE.[Desc]
FROM #SOURCE
WHERE #DEST.[ID] = #SOURCE.[ID];
4
  • 1
    ДА - нет специального JOIN и НЕТ - это не может быть применено к табличным переменным. 26 янв.
  • 1
    Я думаю, что если вы используете [_id] в своем #SOURCE, а не [ID] такой же, как # DESTINATION, они могут позволить вам выполнить JOIN. "на # DESTINATION.ID = # SOURCE._id. Или даже используйте табличную переменную, такую ​​как @tbl," на [email protected]_id ". Вы пробовали? Я использую телефон, чтобы ответить на этот вопрос, а не компьютер, чтобы попробовать . 3 фев '17 в 15:53
  • 2
    Какое это имеет отношение к обновлению из SELECT? 5 фев '17 в 18:10
  • 2
    Это та же идея, но другой метод - вам вообще не нужно ставить «select» для достижения JOIN и WHERE в операторе обновления - это тип запроса SELECT, даже не записывая SELECT. 5 фев '17 в 18:19
22

Использовать:

drop table uno
drop table dos

create table uno
(
    uid int,
    col1 char(1),
    col2 char(2)
)
create table dos
(
    did int,
    col1 char(1),
    col2 char(2),
    [sql] char(4)
)
insert into uno(uid) values (1)
insert into uno(uid) values (2)
insert into dos values (1,'a','b',null)
insert into dos values (2,'c','d','cool')

select * from uno 
select * from dos

ИЛИ:

update uno set col1 = (select col1 from dos where uid = did and [sql]='cool'), 
col2 = (select col2 from dos where uid = did and [sql]='cool')

ИЛИ:

update uno set col1=d.col1,col2=d.col2 from uno 
inner join dos d on uid=did where [sql]='cool'

select * from uno 
select * from dos

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

update uno set col1 = (select col1 from dos d where uno.[id] = d.[id] and [sql]='cool'),
col2  = (select col2 from dos d where uno.[id] = d.[id] and [sql]='cool')
16

В принятом ответе после:

SET
Table_A.col1 = Table_B.col1,
Table_A.col2 = Table_B.col2

Я бы добавил:

OUTPUT deleted.*, inserted.*

Обычно я помещаю все в откат транзакции и использую "OUTPUT": таким образом, я вижу все, что вот-вот должно произойти. Когда я доволен увиденным, я меняю его ROLLBACKна COMMIT.

Обычно мне нужно документировать то, что я сделал, поэтому я использую эту "results to Text"опцию при выполнении откатного запроса и сохраняю как сценарий, так и результат ВЫХОДА. (Конечно, это непрактично, если я изменил слишком много строк)

14
UPDATE table AS a
INNER JOIN table2 AS b
ON a.col1 = b.col1
INNER JOIN ... AS ...
ON ... = ...
SET ...
WHERE ...
0
14

Приведенное ниже решение работает для базы данных MySQL:

UPDATE table1 a , table2 b 
SET a.columname = 'some value' 
WHERE b.columnname IS NULL ;
0
13

Другой способ обновления из оператора выбора:

UPDATE A
SET A.col = A.col,B.col1 = B.col1
FROM  first_Table AS A
INNER JOIN second_Table AS B  ON A.id = B.id WHERE A.col2 = 'cool'
1
  • Этот ответ оказался в очереди на проверку низкого качества, предположительно из-за того, что вы не предоставили никакого объяснения кода. Если этот код отвечает на вопрос, подумайте о добавлении текста, объясняющего код, в свой ответ. Таким образом, у вас гораздо больше шансов получить больше голосов и помочь человеку, задавшему вопрос, узнать что-то новое.
    lmo
    8 сен '16 в 22:09
10

Вариант 1. Использование внутреннего соединения:

UPDATE
    A
SET
    A.col1 = B.col1,
    A.col2 = B.col2
FROM
    Some_Table AS A
    INNER JOIN Other_Table AS B
        ON A.id = B.id
WHERE
    A.col3 = 'cool'

Вариант 2: сопутствующий подзапрос

UPDATE table 
SET Col1 = B.Col1, 
    Col2 = B.Col2 
FROM (
    SELECT ID, Col1, Col2 
    FROM other_table) B
WHERE 
    B.ID = table.ID
3
  • Это сработало для вас? Я использовал тот же запрос, но имел ошибки при использовании внутреннего соединения, псевдоним не разрешается. Однако связанный подзапрос работал отлично. 26 ноя '19 в 15:12
  • У меня нет точных журналов ошибок, но псевдоним A использовался до назначения, что вызвало ошибку. 07 янв.
  • Я использовал коррелированный подзапрос 19 марта '20 в 21: 142020-03-19 18:14
7
UPDATE table1
SET column1 = (SELECT expression1
               FROM table2
               WHERE conditions)
[WHERE conditions];

Синтаксис оператора UPDATE при обновлении одной таблицы данными из другой таблицы в SQL Server

7

Важно отметить, что, как и другие, MySQL или MariaDB используют другой синтаксис. Также он поддерживает очень удобный синтаксис USING (в отличие от T / SQL). Также INNER JOIN является синонимом JOIN. Поэтому запрос в исходном вопросе лучше всего реализовать в MySQL следующим образом:

UPDATE
    Some_Table AS Table_A

JOIN
    Other_Table AS Table_B USING(id)

SET
    Table_A.col1 = Table_B.col1,
    Table_A.col2 = Table_B.col2

WHERE
    Table_A.col3 = 'cool'

Я не видел решения заданного вопроса в других ответах, поэтому мои два цента. (проверено на PHP 7.4.0 MariaDB 10.4.10)