PostgreSQL에서 업데이트 + 가입을 수행하는 방법은 무엇입니까?


508

기본적으로 나는 이것을하고 싶다 :

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


5
Postgres 구문이 다릅니다 : postgresql.org/docs/8.1/static/sql-update.html
Marc B

4
vehicle_vehicle, 선적 _ 배송? 흥미로운 테이블 명명 규칙
CodeAndCats

3
@CodeAndCats Haha ... 재미 있지 않나요? 나는 당시 장고를 사용하고 있다고 생각하며 테이블은 기능별로 그룹화되어 있습니다. 뷰 vehicles_*테이블과 몇 개의 shipments_*테이블 이 있었을 것 입니다.
mpen

답변:


776

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 

업데이트가 전체 테이블 조인 목록에 의존하는 경우 UPDATE 섹션 또는 FROM 섹션에 있어야합니까?
ted.strauss

11
@ ted.strauss : FROM은 테이블 목록을 포함 할 수 있습니다.
Mark Byers

140

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

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

그러므로. 다음 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하위 쿼리에서와 같이 더 이상 자체적 으로 테이블을 지정할 필요가 없습니다 .


16
세 번째 테이블에 어떻게 참여 하시겠습니까?
Growler

19
당신은 단지 JOIN그것에서 평소와 같이 FROM목록 :FROM abiturients b JOIN addresses c ON c.abiturient_id = b.id
Envek

@ Envek-당신은 슬프게도 JOIN을 사용할 수 없습니다. 방금 확인했습니다. postgresql.org/docs/10/static/sql-update.html
Adrian Smith

3
@AdrianSmith의 경우 UPDATE 자체에서 JOIN을 사용할 수 없지만 UPDATE의 from_list절 (PostgreSQL의 SQL 확장) 에서 사용할 수 있습니다 . 또한 제공 한 링크에서 테이블 조인주의 사항을 참조하십시오.
Envek

@Envek-아, 설명해 주셔서 감사합니다.
Adrian Smith

130

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


1
필자는 항상 "select"를 맨 위로 가져 와서 "update", 특히 여러 조인으로 바꾸는 데 약간의 긴장이 있기 때문에 이것을 좋아합니다. 이렇게하면 대량 업데이트 전에 수행해야 할 SQL 덤프 수가 줄어 듭니다. :)
dannysauer

5
이유는 확실하지 않지만이 쿼리의 CTE 버전은 위의 "일반 조인"솔루션보다 훨씬 빠릅니다.
paul.ago

이 솔루션의 다른 장점은 with / select 문에서 여러 조인을 사용하여 둘 이상의 테이블에서 조인하여 최종 계산 된 값에 도달 할 수 있다는 것입니다.
Alex Muro

1
대단해. 나는 내 선택을 만들었고 @dannysauer처럼 변환이 무서웠다. 이것은 단순히 나를 위해 그것을합니다. 완전한!
frostymarvelous

1
첫 번째 SQL 예제에 구문 오류가 있습니다. "update t1"은 t 서브 쿼리의 별명을 사용할 수 없으며 테이블 이름 "update table1"을 사용해야합니다. 두 번째 예제에서 올바르게 수행하십시오.
EricS

80

실제로하고 싶은 사람들을 위해 다음 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"테이블에서 온 것으로 간주되므로 테이블 참조가 필요하지 않습니다.


4
이것이 실제 조인이있는 첫 번째 답변 (및 하위 쿼리가 아닌)을 고려할 때, 이것은 실제로 허용되는 답변이어야합니다. postgresql이 업데이트에서 조인을 지원하는지 여부를 혼동하지 않도록이 질문 또는이 질문의 이름을 바꿔야합니다.
목걸이

효과가있다. 그러나 해킹 같은 느낌
M. Habib

문서 ( postgresql.org/docs/11/sql-update.html )에 따라 from 절에 대상 테이블을 나열하면 대상 테이블이 자체 결합됩니다. 자신도 모르게, 의도하지 않은 결과 및 / 또는 성능에 영향을 줄 수있는 상호 자조 인 것 같습니다.
벤 콜린스

14

조인이 반환하는 행만 업데이트하는 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;

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


7

여기 우리는 간다 :

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"부분에 별칭을 사용할 수 없습니다.


@littlegreen 확실합니까? 는하지 않습니다 join를 제한?
mpen

4
@mpen 모든 레코드를 하나의 값으로 업데이트한다는 것을 확인할 수 있습니다. 그것은 당신이 기대하는 것을하지 않습니다.
Adam Bell

1

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

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


0

첫 번째 테이블 이름 : tbl_table1 (tab1). 두 번째 테이블 이름 : tbl_table2 (tab2).

tbl_table1의 ac_status 열을 "INACTIVE"로 설정하십시오.

update common.tbl_table1 as tab1
set ac_status= 'INACTIVE' --tbl_table1's "ac_status"
from common.tbl_table2 as tab2
where tab1.ref_id= '1111111' 
and tab2.rel_type= 'CUSTOMER';
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.