[postgresql] 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에서 어떻게 작성합니까?



답변

UPDATE 구문 입니다 :

[WITH [RECURSIVE] with_query [, ...]]
UPDATE [ONLY] 테이블 [[AS] alias]
    SET {column = {표현식 | 기본} |
          (column [, ...]) = ({expression | DEFAULT} [, ...])} [, ...]
    [FROM from_list]
    [여기서 조건 | cursor_name의 현재 위치]
    [반품 * | 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 


답변

예를 들어 조금 더 설명하겠습니다.

과제 : 모든 정보 (중등 학교를 떠나려는 학생)가 학교 증명서를받은 것보다 일찍 대학에 신청서를 제출 한 올바른 정보 (예, 증명서를받은 것보다 발급 된 것보다 일찍 (인증서가 지정된 날짜)) 인증서 발급 날짜에 맞게 신청서 제출 날짜를 늘리십시오.

그러므로. 다음 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

보시다시피, 원래 하위 쿼리 JOINON절은 다른 쿼리와 함께 사용 WHERE되는 조건 중 하나 AND가되었으며 변경없이 하위 쿼리에서 이동되었습니다. 그리고 JOIN하위 쿼리에서와 같이 더 이상 자체적 으로 테이블을 지정할 필요가 없습니다 .


답변

이 상황에서 Mark Byers의 답변이 최적입니다. 더 복잡한 상황에서는 rowid와 계산 된 값을 반환하는 select 쿼리를 사용하여 다음과 같이 업데이트 쿼리에 연결할 수 있습니다.

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 table1
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은 열 이름의 모호성에 대해 불평합니다.


답변

실제로하고 싶은 사람들을 위해 다음 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;

SET필요한 경우 등호 오른쪽의 섹션에서 a_alias를 사용할 수 있습니다 . 등호 왼쪽에있는 필드는 원래 “a”테이블에서 온 것으로 간주되므로 테이블 참조가 필요하지 않습니다.


답변

조인이 반환하는 행만 업데이트하는 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
--the below line is critical for updating ONLY joined rows
AND a.pk_id = a_alias.pk_id;

이것은 위에서 언급되었지만 의견을 통해서만 언급되었습니다. 정확한 결과를 게시하는 것이 중요하기 때문에 작동합니다.


답변

여기 우리는 간다 :

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

내가 할 수있는 것처럼 간단합니다. 고마워요!

또한 이것을 할 수 있습니다 :

-- Doesn't work apparently
update vehicles_vehicle
set price=s.price_per_vehicle
from vehicles_vehicle v
join shipments_shipment s on v.shipment_id=s.id;

그러나 비히클 테이블이 두 번 있고, 한 번만 별칭을 사용할 수 있으며 “set”부분에 별칭을 사용할 수 없습니다.


답변

다음은 Name의 Middle_Name 필드를 사용하여 Name3 테이블에서 Mid_Name을 업데이트하는 간단한 SQL입니다.

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