Как я могу сделать оператор UPDATE с JOIN в SQL Server?

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

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

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

Таблица: уд

id  (int)
assid  (int)

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

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

18.08.2009 11:40:07
Какие СУБД вы используете? MySQL, SQL Server, Oracle, PostgreSQL или что-то еще?
Chris J 18.08.2009 11:41:58
какие отношения между таблицами? Как узнать, какая запись из продажи соответствует какой записи из ud? Это основано на id как первичный ключ в обеих таблицах?
Cătălin Pitiș 18.08.2009 11:43:27
Как вы можете обновить UD? У него есть только идентификатор и собственный идентификатор. Не могли бы вы привести пример с точки зрения существующих значений, а также записей, которые вы хотели бы изменить или добавить в результате выполнения сценария?
Bernhard Hofmann 18.08.2009 11:43:52
Смотрите также ТАК вопрос ... stackoverflow.com/questions/982919/sql-update-query-using-joins
SteveC 14.06.2013 14:48:57
Псевдоним пользователя в запросе, например stackoverflow.com/questions/982919/sql-update-query-using-joins
Imran Muhammad 15.08.2017 11:46:35
16 ОТВЕТОВ
РЕШЕНИЕ

Синтаксис строго зависит от того, какую СУБД 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.

Oracle:

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
 );
2371
10.03.2020 03:56:40
Мне кажется, что MySQL set assid = s.assidдолжен быть set u.assid = s.assid.
dotancohen 17.04.2012 21:44:51
В синтаксисе ANSI, что произойдет, если SELECT после =возврата более одной строки?
Throw Away Account 5.05.2017 17:49:26
@ ThrowawayAccount3Million Это, вероятно, не удастся. AFAIK, этот вид операции будет ожидать скалярное значение и выдаст ошибку, если вместо этого будет задан набор результатов.
Francis Lord 16.05.2017 16:31:38
Я хотел бы, чтобы ОП выбрал несколько лучших имен для своей таблицы и столбцов !! это не такой читаемый / интуитивно понятный ...
S.Serpooshan 31.12.2018 12:07:25
Postgre 9.3 работал только с использованиемupdate ud set assid = s.assid
StackUnder 15.05.2019 15:47:32

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

update ud 
set assid = sale.assid
from sale
where sale.udid = id
142
31.08.2017 19:32:50

Стандартный подход 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
48
18.08.2009 12:34:52
С первым вы не можете сопоставить более 2 столбцов, но объединение работает отлично.
makciook 11.07.2013 08:28:01
@ makciook: а? Вы можете просто добавить больше условий в WHEREпредложении, если хотите сопоставить дополнительные столбцы.
siride 11.07.2015 05:32:17
Просто гнида ... но я думаю, что ОП означало sale.udid = ud.id. И не распродажа.
Skippy VonDrake 14.01.2017 18:40:31

Еще один пример, почему 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]
15
16.11.2009 19:17:16
+1 к комментарию «почему SQL не очень переносимый»! Переносимость настолько хрупка, что простое объявление переменной нарушит переносимость многих популярных механизмов баз данных.
Jeff Moden 26.01.2013 00:55:08

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 
97
9.11.2015 13:26:21
Ответ был бы более удобен, если бы он использовал имена таблиц / столбцов, используемые в вопросе. Почему в вашем ответе 3 таблицы?
alfonx 7.03.2014 21:28:31

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;
38
8.05.2014 07:52:18

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
8
3.07.2014 10:22:18

Упрощенный запрос на обновление с использованием 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, являются именами демонстрационных таблиц, именами столбцов и идентификаторами. Замените их действительными именами.

25
14.07.2014 07:15:25

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

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

update ud
set u.assid = s.assid
from ud u
    inner join sale s on
        u.id = s.udid
8
19.11.2014 08:24:18

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

UPDATE users 
set users.DivisionId=divisions.DivisionId
from divisions join users on divisions.Name=users.Division
7
6.04.2016 11:34:28
UPDATE tblAppraisalBasicData
SET tblAppraisalBasicData.ISCbo=1
FROM tblAppraisalBasicData SI INNER JOIN  aaa_test RAN ON SI.EmpID = RAN.ID
3
19.12.2016 11:40:06

И в MS ACCESS:

UPDATE ud 
INNER JOIN sale ON ud.id = sale.udid
SET ud.assid = sale.assid;
4
7.03.2017 18:38:28
В качестве предостережения, SET должен прийти сразу после определения набора записей! Я только что пытался разработать аналогичный сценарий в базе данных Access, для которой требовалось предложение WHERE (оно не принимало бы его в качестве допустимого условия ON). ГДЕ должен был прийти последним, чтобы избежать синтаксических ошибок.
Dodecaphone 29.05.2019 14:50:10

MySQL

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

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

пример

сценарий

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

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

запрос

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 раза, чтобы увидеть, должно ли оно присоединиться, и потенциально вернуть намного больше строк. Однако, предоставляя ему больше условий, он может «пропустить» много строк, если они не удовлетворяют всем условиям при соединении.

бонус

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

7
9.02.2018 16:57:54

Для 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');
2
13.10.2018 16:04:59
Не могли бы вы объяснить это немного?
Mohammed Noureldin 8.10.2018 13:29:06
@MohammedNoureldin Я постараюсь объяснить. Проблема заключается в том, как обновить таблицу с результатом запроса в соединении, используя ту же таблицу. Оператор (sub-select) действует как соединение и возвращает системное поле RowID, которое является уникальным числом для каждой строки в таблице. Поскольку суб-выбор может возвращать несколько строк, «где RowID =» выбирает единственную правильную строку из результирующего суб-выбора и выполняет обновление столбца. Дайте мне знать, если вам нужно больше разъяснений или нужно выяснить вариации на эту тему.
KeithTheBiped 13.10.2018 16:16:24

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

update ud

set ud.assid = sale.assid

from ud 

Inner join sale on ud.id = sale.udid

where sale.udid is not null
3
23.11.2018 15:42:18

Самый простой способ - использовать Общее табличное выражение (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
4
23.04.2019 17:07:19