Как сделать обновление + присоединиться к PostgreSQL?

В принципе, я хочу сделать это:

update vehicles_vehicle v 
    join shipments_shipment s on v.shipment_id=s.id 
set v.price=s.price_per_vehicle;

Я уверен, что будет работать в MySQL (мой фон), но он не работает в postgres. Ошибка, которую я получаю:

ERROR:  syntax error at or near "join"
LINE 1: update vehicles_vehicle v join shipments_shipment s on v.shi...
                                  ^

Конечно, есть простой способ сделать это, но я не могу найти правильный синтаксис. Итак, как бы я написал это в PostgreSQL?

Ответ 1

Синтаксис UPDATE:

[ WITH [ RECURSIVE ] with_query [, ...] ]
UPDATE [ ONLY ] table [ [ AS ] alias ]
    SET { column = { expression | DEFAULT } |
          ( column [, ...] ) = ( { expression | DEFAULT } [, ...] ) } [, ...]
    [ FROM from_list ]
    [ WHERE condition | WHERE CURRENT OF cursor_name ]
    [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]

В вашем случае я думаю, что вы этого хотите:

UPDATE vehicles_vehicle AS v 
SET price = s.price_per_vehicle
FROM shipments_shipment AS s
WHERE v.shipment_id = s.id 

Ответ 2

Позвольте мне объяснить немного больше моим примером.

Задача: верная информация, где abiturients (студенты, которые покинут среднюю школу) подали заявки в университет раньше, чем получили школьные сертификаты (да, они получили сертификаты раньше, чем они были выпущены (по дате сертификата)., мы увеличим дату подачи заявки до даты выпуска сертификата.

Таким образом. следующий MySQL-подобный оператор:

UPDATE applications a
JOIN (
    SELECT ap.id, ab.certificate_issued_at
    FROM abiturients ab
    JOIN applications ap 
    ON ab.id = ap.abiturient_id 
    WHERE ap.documents_taken_at::date < ab.certificate_issued_at
) b
ON a.id = b.id
SET a.documents_taken_at = b.certificate_issued_at;

Становится PostgreSQL-подобным способом

UPDATE applications a
SET documents_taken_at = b.certificate_issued_at         -- we can reference joined table here
FROM abiturients b                                       -- joined table
WHERE 
    a.abiturient_id = b.id AND                           -- JOIN ON clause
    a.documents_taken_at::date < b.certificate_issued_at -- Subquery WHERE

Как вы можете видеть, исходный подзапрос JOIN ON стал одним из условий WHERE, который соединен с AND с другими, которые были перемещены из подзапроса без изменений. И больше нет необходимости в таблице JOIN с самим собой (как это было в подзапросе).

Ответ 3

Ответ Марк Байерс является оптимальным в этой ситуации. Хотя в более сложных ситуациях вы можете взять запрос выбора, который возвращает rowids и вычисленные значения, и присоединить его к запросу обновления, например:

with t as (
  -- Any generic query which returns rowid and corresponding calculated values
  select t1.id as rowid, f(t2, t2) as calculatedvalue
  from table1 as t1
  join table2 as t2 on t2.referenceid = t1.id
)
update t1
set value = t.calculatedvalue
from t
where id = t.rowid

Этот подход позволяет вам разрабатывать и тестировать ваш запрос выбора и в два этапа преобразовывать его в запрос обновления.

Итак, в вашем случае запрос результата будет:

with t as (
    select v.id as rowid, s.price_per_vehicle as calculatedvalue
    from vehicles_vehicle v 
    join shipments_shipment s on v.shipment_id = s.id 
)
update vehicles_vehicle
set price = t.calculatedvalue
from t
where id = t.rowid

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

Ответ 4

Для тех, кто действительно хочет JOIN вы также можете использовать:

UPDATE a
SET price = b_alias.unit_price
FROM      a AS a_alias
LEFT JOIN b AS b_alias ON a_alias.b_fk = b_alias.id
WHERE a_alias.unit_name LIKE 'some_value' 
AND a.id = a_alias.id;

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

Ответ 5

Здесь мы идем:

update vehicles_vehicle v
set price=s.price_per_vehicle
from shipments_shipment s
where v.shipment_id=s.id;

Просто, как я мог это сделать. Спасибо, ребята!

Также можно сделать следующее:

update vehicles_vehicle 
set price=s.price_per_vehicle
from vehicles_vehicle v
join shipments_shipment s on v.shipment_id=s.id;

Но тогда у вас есть табличка с транспортным средством там дважды, и вам разрешено только псевдоним, и вы не можете использовать псевдоним в разделе "set".

Ответ 6

Вот простой SQL, который обновляет Mid_Name в таблице Name3, используя поле Middle_Name из Name:

update name3
set mid_name = name.middle_name
from name
where name3.person_id = name.person_id;

Ответ 7

Для тех, кто хочет создать JOIN, который обновляет ТОЛЬКО строки, которые использует ваше соединение:

UPDATE a
SET price = b_alias.unit_price
FROM      a AS a_alias
LEFT JOIN b AS b_alias ON a_alias.b_fk = b_alias.id
WHERE a_alias.unit_name LIKE 'some_value' 
AND a.id = a_alias.id
AND a.pk_id = a_alias.pk_id;

Это было упомянуто выше, но только через комментарий. Поскольку очень важно получить правильный результат, публикуя НОВЫЙ ответ, который работает