Как я могу выполнить инструкцию UPDATE с JOIN в SQL Server?

avatar
Ant Swift
18 августа 2009 в 11:40
1712798
16
1439

Мне нужно обновить эту таблицу в SQL Server данными из его «родительской» таблицы, см. Ниже:

Стол: продажа

id (int)
udid (int)
assid (int)

Таблица: ud

id  (int)
assid  (int)

sale.assid содержит правильное значение для обновления ud.assid.

Какой запрос сделает это? Я думаю о join, но не уверен, возможно ли это.

Источник
Cătălin Pitiș
18 августа 2009 в 11:43
0

какие отношения между таблицами? Как узнать, какая запись из продажи соответствует какой записи из ud? Основан ли он на идентификаторе в качестве первичного ключа в обеих таблицах?

Bernhard Hofmann
18 августа 2009 в 11:43
0

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

SteveC
14 июня 2013 в 14:48
2

См. Также вопрос SO ... coderhelper.com/questions/982919/sql-update-query-using-joins

Imran Muhammad
15 августа 2017 в 11:46
2

Псевдоним пользователя в запросе типа coderhelper.com/questions/982919/sql-update-query-using-joins

Ответы (16)

avatar
Eric
18 августа 2009 в 11:44
2585

Синтаксис строго зависит от того, какую СУБД SQL вы используете. Вот несколько способов сделать это в ANSI / ISO (он же должен работать с любой СУБД SQL), MySQL, SQL Server и Oracle. Имейте в виду, что предлагаемый мной метод ANSI / ISO обычно будет намного медленнее, чем два других метода, но если вы используете СУБД SQL, отличную от MySQL, SQL Server или Oracle, тогда это может быть единственный способ (например, если ваша СУБД SQL не поддерживает MERGE):

ANSI / ISO:

update ud 
     set assid = (
          select sale.assid 
          from sale 
          where sale.udid = ud.id
     )
 where exists (
      select * 
      from sale 
      where sale.udid = ud.id
 );

MySQL:

update ud u
inner join sale s on
    u.id = s.udid
set u.assid = s.assid

SQL Server:

update u
set u.assid = s.assid
from ud u
    inner join sale s on
        u.id = s.udid

PostgreSQL:

update ud
  set assid = s.assid
from sale s 
where ud.id = s.udid;

Обратите внимание, что целевая таблица не должна повторяться в предложении FROM для Postgres.

Оракул:

update
    (select
        u.assid as new_assid,
        s.assid as old_assid
    from ud u
        inner join sale s on
            u.id = s.udid) up
set up.new_assid = up.old_assid

SQLite:

update ud 
     set assid = (
          select sale.assid 
          from sale 
          where sale.udid = ud.id
     )
 where RowID in (
      select RowID 
      from ud 
      where sale.udid = ud.id
 );
dotancohen
17 апреля 2012 в 21:44
3

Мне кажется, что MySQL set assid = s.assid должен быть set u.assid = s.assid.

Throw Away Account
5 мая 2017 в 17:49
2

Что произойдет в синтаксисе ANSI, если SELECT после = вернет более одной строки?

Francis Lord
16 мая 2017 в 16:31
2

@ ThrowawayAccount3Million Вероятно, он потерпит неудачу. AFAIK, этот вид операции будет ожидать скалярного значения и вызовет ошибку, если вместо этого будет предоставлен набор результатов.

toto_tico
11 мая 2018 в 11:36
2

@PrabakaranRaja, ANSI/ISO ответ работает для sqlite3.

S.Serpooshan
31 декабря 2018 в 12:07
11

Я хочу, чтобы ОП выбрал лучшие имена для своей таблицы и столбцов !! он не такой читабельный / интуитивно понятный ...

StackUnder
15 мая 2019 в 15:47
4

Postgre 9.3 работал только с update ud set assid = s.assid

avatar
Kemal AL GAZZAH
23 апреля 2019 в 17:07
5

Самый простой способ - использовать Common Table Expression (CTE), представленный в SQL 2005

with cte as
(select u.assid col1 ,s.assid col2 from ud u inner join sale s on u.id = s.udid)
update cte set col1=col2
avatar
HARSHIT RATHORE
23 ноября 2018 в 13:42
4

Попробуйте это, я думаю, это сработает для вас

update ud

set ud.assid = sale.assid

from ud 

Inner join sale on ud.id = sale.udid

where sale.udid is not null
avatar
KeithTheBiped
13 мая 2018 в 14:45
3

Для SQLite используйте свойство RowID, чтобы выполнить обновление:

update Table set column = 'NewValue'
where RowID = 
(select t1.RowID from Table t1
join Table2 t2 on t1.JoinField = t2.JoinField
where t2.SelectValue = 'FooMyBarPlease');
Mohammed Noureldin
8 октября 2018 в 13:29
1

Не могли бы вы немного это объяснить?

KeithTheBiped
13 октября 2018 в 16:16
1

@MohammedNoureldin Я постараюсь объяснить. Проблема в том, как обновить таблицу с помощью результата запроса при соединении с использованием той же таблицы. Оператор (sub-select) действует как соединение и возвращает системное поле RowID, которое является уникальным номером для каждой строки в таблице. Поскольку подвыбор может возвращать несколько строк, "where RowID =" выбирает единственную правильную строку из результирующего подвыбора и обновляет столбец. Дайте мне знать, если вам нужны дополнительные разъяснения или нужно найти вариант по этой теме.

Mark E.
2 февраля 2021 в 06:57
1

Очень полезно - использование RowID сделало это намного быстрее, чем мои предыдущие попытки без него.

avatar
Luke Watts
9 февраля 2018 в 16:57
8

MySQL

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

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

Пример

Сценарий

У вас есть таблица пользователей. Они могут войти в систему, используя свое имя пользователя, адрес электронной почты или номер учетной записи. Эти учетные записи могут быть активными (1) или неактивными (0). В этой таблице 50000 строк

Затем у вас есть таблица пользователей, которую нужно отключить сразу, потому что вы обнаруживаете, что все они сделали что-то плохое. Однако в этой таблице есть один столбец со смешанными именами пользователей, адресами электронной почты и номерами счетов. У него также есть индикатор has_run, который должен быть установлен на 1 (истина), когда он был запущен

Запрос

UPDATE users User
    INNER JOIN
        blacklist_users BlacklistUser
        ON
        (
            User.username = BlacklistUser.account_ref
            OR
            User.email = BlacklistedUser.account_ref
            OR
            User.phone_number = BlacklistUser.account_ref
            AND
            User.is_active = 1
            AND
            BlacklistUser.has_run = 0
        )
    SET
        User.is_active = 0,
        BlacklistUser.has_run = 1;

Рассуждения

Если бы нам нужно было присоединиться только по условиям ИЛИ, то по существу нужно было бы проверять каждую строку 4 раза, чтобы увидеть, должна ли она присоединиться, и, возможно, вернуть намного больше строк. Однако, задав ему больше условий, он может «пропустить» много строк, если они не удовлетворяют всем условиям при объединении.

Бонус

Это более читабельно. Все условия находятся в одном месте, а строки для обновления - в одном месте

avatar
Richard
7 марта 2017 в 18:38
4

И в MS ACCESS:

UPDATE ud 
INNER JOIN sale ON ud.id = sale.udid
SET ud.assid = sale.assid;
Dodecaphone
29 мая 2019 в 14:50
1

В качестве предостережения, SET должен идти сразу после определения набора записей! Я только что пытался разработать аналогичный сценарий в базе данных Access, для которой требовалось предложение WHERE (оно не приняло бы его как допустимое условие ON). WHERE должен был быть последним, чтобы избежать синтаксических ошибок.

avatar
Abdullah Yousuf
19 декабря 2016 в 11:38
3
UPDATE tblAppraisalBasicData
SET tblAppraisalBasicData.ISCbo=1
FROM tblAppraisalBasicData SI INNER JOIN  aaa_test RAN ON SI.EmpID = RAN.ID
avatar
Sheryar Nizar
6 апреля 2016 в 11:34
8

Следующий оператор с ключевым словом FROM используется для обновления нескольких строк с помощью соединения

UPDATE users 
set users.DivisionId=divisions.DivisionId
from divisions join users on divisions.Name=users.Division
avatar
Ken Goh
19 ноября 2014 в 08:24
8

Я думал, что SQL-Server в верхнем посте подойдет для Sybase, поскольку они оба являются T-SQL, но, к сожалению, нет.

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

update ud
set u.assid = s.assid
from ud u
    inner join sale s on
        u.id = s.udid
avatar
Vinit Kadkol
14 июля 2014 в 07:15
26

Упрощенный запрос обновления с использованием JOIN для нескольких таблиц.

   UPDATE
        first_table ft
        JOIN second_table st ON st.some_id = ft.some_id
        JOIN third_table tt  ON tt.some_id = st.some_id
        .....
    SET
        ft.some_column = some_value
    WHERE ft.some_column = 123456 AND st.some_column = 123456

Примечание - first_table, second_table, third_table и some_column, например 123456, являются именами демонстрационных таблиц, именами столбцов и идентификаторами. Замените их действительными именами.

Source Matters
7 октября 2020 в 22:19
1

Неверный синтаксис для MS SQL.

avatar
xhudik
3 июля 2014 в 10:22
10

Teradata Aster предлагает еще один интересный способ достижения цели:

MERGE INTO ud --what trable should be updated
USING sale -- from what table/relation update info should be taken
ON ud.id = sale.udid --join condition
WHEN MATCHED THEN 
    UPDATE SET ud.assid = sale.assid; -- how to update
avatar
alfonx
7 марта 2014 в 21:35
39

PostgreSQL:

CREATE TABLE ud (id integer, assid integer);
CREATE TABLE sales (id integer, udid integer, assid integer);

UPDATE ud
SET assid = sales.assid
FROM sales
WHERE sales.id = ud.id;
avatar
user1154043
17 января 2012 в 13:53
103

postgres

UPDATE table1
SET    COLUMN = value
FROM   table2,
       table3
WHERE  table1.column_id = table2.id
       AND table1.column_id = table3.id
       AND table1.COLUMN = value
       AND table2.COLUMN = value
       AND table3.COLUMN = value 
alfonx
7 марта 2014 в 21:28
22

Ответ был бы более удобным, если бы он использовал имена таблиц / столбцов, используемые в вопросе. Почему в вашем ответе 3 таблицы?

avatar
Yada
16 ноября 2009 в 19:17
17

Еще один пример того, почему SQL не совсем переносим.

Для MySQL это будет:

update ud, sale
set ud.assid = sale.assid
where sale.udid = ud.id;

Для получения дополнительной информации прочтите обновление нескольких таблиц: http://dev.mysql.com/doc/refman/5.0/en/update.html

UPDATE [LOW_PRIORITY] [IGNORE] table_references
    SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ...
    [WHERE where_condition]
Jeff Moden
26 января 2013 в 00:55
2

+1 к комментарию «почему SQL на самом деле не переносится»! Переносимость настолько хрупка, что простое объявление переменной нарушит переносимость многих популярных движков баз данных.

avatar
MattH
18 августа 2009 в 11:44
51

Стандартный подход SQL:

UPDATE ud
SET assid = (SELECT assid FROM sale s WHERE ud.id=s.id)

На SQL Server вы можете использовать соединение

UPDATE ud
SET assid = s.assid
FROM ud u
JOIN sale s ON u.id=s.id
makciook
11 июля 2013 в 08:28
1

С первым вы не можете сопоставить 2+ столбца, но объединение отлично работает.

siride
11 июля 2015 в 05:32
6

@makciook: а? Вы можете просто добавить дополнительные условия в предложение WHERE, если хотите сопоставить дополнительные столбцы.

Skippy VonDrake
14 января 2017 в 18:40
3

Просто гнида ... но я думаю, что OP имел в виду sale.udid = ud.id. И не sale.id.

avatar
edosoft
18 августа 2009 в 11:42
151

Это должно работать в SQL Server:

update ud 
set assid = sale.assid
from sale
where sale.udid = id