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

1315

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

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

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

Таблица: уд

id  (int)
assid  (int)

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

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

Муравей Свифт
источник
3
Какие СУБД вы используете? MySQL, SQL Server, Oracle, PostgreSQL или что-то еще?
Крис Дж
какие отношения между таблицами? Как узнать, какая запись из продажи соответствует какой записи из ud? Это основано на идентификаторе как первичный ключ в обеих таблицах?
Кэтэлин Питиș
Как вы можете обновить UD? У него есть только идентификатор и собственный идентификатор. Не могли бы вы привести пример с точки зрения существующих значений, а также записей, которые вы хотели бы изменить или добавить в результате выполнения сценария?
Бернхард Хофманн
2
См. Также ТАК вопрос ... stackoverflow.com/questions/982919/sql-update-query-using-joins
SteveC
2
Псевдоним пользователя в запросе, например stackoverflow.com/questions/982919/sql-update-query-using-joins
Имран Мухаммад

Ответы:

2383

Синтаксис строго зависит от того, какую СУБД 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
 );
Эрик
источник
3
Мне кажется, что MySQL set assid = s.assidдолжен быть set u.assid = s.assid.
dotancohen
2
В синтаксисе ANSI, что произойдет, если SELECT после =возвращает более одной строки?
счет
2
@ ThrowawayAccount3Million Это, вероятно, не удастся. AFAIK, этот вид операции будет ожидать скалярное значение и выдаст ошибку, если вместо этого будет задан набор результатов.
Фрэнсис Лорд
6
Я хотел бы, чтобы ОП выбрал несколько лучших имен для своей таблицы и столбцов !! это не такой читабельный / интуитивно понятный ...
S.Serpooshan
4
Postgre 9.3 работал только с использованиемupdate ud set assid = s.assid
StackUnder
143

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

update ud 
set assid = sale.assid
from sale
where sale.udid = id
edosoft
источник
98

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 
user1154043
источник
20
Ответ был бы более удобен, если бы он использовал имена таблиц / столбцов, используемые в вопросе. Почему в вашем ответе 3 таблицы?
alfonx
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
Matth
источник
1
С первым вы не можете сопоставить более 2 столбцов, но объединение работает отлично.
makciook
6
@ makciook: а? Вы можете просто добавить больше условий в WHEREпредложении, если хотите сопоставить дополнительные столбцы.
Сирида
2
Просто гнида ... но я думаю, что ОП означало sale.udid = ud.id. И не распродажа.
Skippy VonDrake
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;
alfonx
источник
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, являются именами демонстрационных таблиц, именами столбцов и идентификаторами. Замените их действительными именами.

Винит Кадкол
источник
16

Еще один пример, почему 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]
Яда
источник
2
+1 к комментарию «почему SQL не очень переносимый»! Переносимость настолько хрупка, что простое объявление переменной нарушит переносимость многих популярных механизмов баз данных.
Джефф Моден
8

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
xhudik
источник
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
Кен Го
источник
7

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

UPDATE users 
set users.DivisionId=divisions.DivisionId
from divisions join users on divisions.Name=users.Division
Шерьяр Низар
источник
7

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

бонус

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

Люк Уоттс
источник
4

И в MS ДОСТУП:

UPDATE ud 
INNER JOIN sale ON ud.id = sale.udid
SET ud.assid = sale.assid;
Ричард
источник
1
В качестве предупреждения, SET должен прийти сразу после определения набора записей! Я только что пытался разработать аналогичный сценарий в базе данных Access, для которой требовалось предложение WHERE (оно не принимало бы его в качестве допустимого условия ON). ГДЕ должен был прийти последним, чтобы избежать синтаксических ошибок.
Додекафон
3
UPDATE tblAppraisalBasicData
SET tblAppraisalBasicData.ISCbo=1
FROM tblAppraisalBasicData SI INNER JOIN  aaa_test RAN ON SI.EmpID = RAN.ID
Абдулла Юсуф
источник
3

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

update ud

set ud.assid = sale.assid

from ud 

Inner join sale on ud.id = sale.udid

where sale.udid is not null
ХАРШИТ РАТХОР
источник
2

Для 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');
KeithTheBiped
источник
1
Не могли бы вы объяснить это немного?
Мухаммед Нурельдин
1
@MohammedNoureldin Я постараюсь объяснить. Проблема заключается в том, как обновить таблицу с результатом запроса на соединение, используя ту же таблицу. Оператор (sub-select) действует как объединение и возвращает системное поле RowID, которое является уникальным числом для каждой строки в таблице. Поскольку дополнительный выбор может возвращать несколько строк, «где RowID =» выбирает одну правильную строку из полученного дополнительного выбора и выполняет обновление столбца. Дайте мне знать, если вам нужно больше разъяснений или нужно выяснить вариации на эту тему.
KeithTheBiped