한 테이블의 SQL 업데이트 필드를 다른 필드의 필드에서


124

두 개의 테이블이 있습니다.

A [ID, column1, column2, column3]
B [ID, column1, column2, column3, column4]

A항상 하위 집합 될 것이다 B(의 모든 열을 의미 A도있다 B).

나는 특정과 기록을 업데이트 할 ID에서 B의 데이터와 A모든 열에 대한 A. 이것은 및에 ID모두 존재합니다 .AB

거기 UPDATE구문이나, 단지 말을 열 이름을 지정하지 않고 그렇게 할 수있는 다른 방법 "A의 모든 열을 설정은" ?

PostgreSQL을 사용하고 있으므로 특정 비표준 명령도 허용됩니다 (그러나 선호되지는 않음).


나는 이것이 당신이하고 싶은 일이라고 생각합니다. dba.stackexchange.com/a/58383
zubair-0

답변:


234

비표준 FROM 절을 사용할 수 있습니다 .

UPDATE b
SET column1 = a.column1,
  column2 = a.column2,
  column3 = a.column3
FROM a
WHERE a.id = b.id
AND b.id = 1

9
질문은 모든 열 이름 지정 하지 않고 수행하는 방법에 대해 묻는 것 입니다. (그리고 내가 너무 생각합니다.)
cluesque

2
@cluesque에 동의하지만이 답변은 테이블의 한 열에있는 값을 다른 테이블의 열에있는 값을 대체하기위한 조회 테이블로 사용하는 훌륭한 방법입니다 ( SO 21657475 참조 ). 따라서 +1 ...
Victoria Stuart

1
b.id = 1이 필요한 이유는 무엇입니까?
YasirAzgar

1
@YasirAzgar b.id = 1은 b의 행이 업데이트되는 것을 제한하는 것입니다. 그렇지 않으면 테이블의 모든 행을 업데이트합니다. 때때로 그것은 당신이 원하는 것일 수 있습니다. 그러나 원래 질문은 b의 특정 행을 업데이트하는 것이 었습니다.
Scott Bailey

이것은 내 특정 문제에 필요한 것입니다. 한 테이블의 열을 다른 테이블의 이름이 다른 열의 값으로 업데이트하는 것입니다.
muad-dweeb

49

질문은 오래되었지만 아직 최선의 답변이 주어지지 않았다고 느꼈습니다.

거기 UPDATE구문 ... 열 이름을 지정하지 않고는 ?

동적 SQL을 사용한 일반 솔루션

조인 할 고유 한 열 ( id예제에서 )을 제외하고는 열 이름을 알 필요가 없습니다 . 내가 생각할 수있는 모든 가능한 코너 케이스에 대해 안정적으로 작동합니다.

이것은 PostgreSQL에만 해당됩니다. 나는 information_schema , 특히 information_schema.columnsSQL 표준에 정의되어 있고 대부분의 주요 RDBMS (Oracle 제외)에 정의 된 table을 기반으로 동적 코드를 작성 하고 있습니다. 그러나 동적 SQL을 실행하는 PL / pgSQL 코드 가 포함 된 DO문 은 완전히 비표준 PostgreSQL 구문입니다.

DO
$do$
BEGIN

EXECUTE (
SELECT
  'UPDATE b
   SET   (' || string_agg(        quote_ident(column_name), ',') || ')
       = (' || string_agg('a.' || quote_ident(column_name), ',') || ')
   FROM   a
   WHERE  b.id = 123
   AND    a.id = b.id'
FROM   information_schema.columns
WHERE  table_name   = 'a'       -- table name, case sensitive
AND    table_schema = 'public'  -- schema name, case sensitive
AND    column_name <> 'id'      -- all columns except id
);

END
$do$;

모든 열에 b대해 일치하는 열이 있다고 가정 하지만 그 반대는 아닙니다. 추가 열을 가질 수 있습니다.ab

WHERE b.id = 123 선택한 행을 업데이트하려면 선택 사항입니다.

SQL 바이올린.

자세한 설명이있는 관련 답변 :

일반 SQL을 사용한 부분 솔루션

공유 열 목록 포함

두 테이블이 공유하는 열 이름 목록을 알고 있어야합니다. 여러 열을 업데이트하는 구문 바로 가기가 있습니다. 여태까지 다른 답변이 제안한 것보다 짧습니다.

UPDATE b
SET   (  column1,   column2,   column3)
    = (a.column1, a.column2, a.column3)
FROM   a
WHERE  b.id = 123    -- optional, to update only selected row
AND    a.id = b.id;

SQL 바이올린.

이 구문은 질문이 제기되기 훨씬 전인 2006 년에 Postgres 8.2에서 도입되었습니다. 설명서의 세부 사항.

관련 :

열 목록 포함 B

경우 의 모든 열이 A정의된다 NOT NULL(반드시 그런 것은 아니지만 B),
그리고 당신이 알고있는 의 열 이름을 B(그러나 반드시 A).

UPDATE b
SET   (column1, column2, column3, column4)
    = (COALESCE(ab.column1, b.column1)
     , COALESCE(ab.column2, b.column2)
     , COALESCE(ab.column3, b.column3)
     , COALESCE(ab.column4, b.column4)
      )
FROM (
   SELECT *
   FROM   a
   NATURAL LEFT JOIN  b -- append missing columns
   WHERE  b.id IS NULL  -- only if anything actually changes
   AND    a.id = 123    -- optional, to update only selected row
   ) ab
WHERE b.id = ab.id;

NATURAL LEFT JOIN에서 행 조인 b같은 이름의 모든 열을 같은 값을 유지 어디에. 이 경우 업데이트가 필요하지 않으며 (변경 사항 없음) 프로세스 초기에 해당 행을 제거 할 수 있습니다 ( WHERE b.id IS NULL).
여전히 일치하는 행을 찾아야하므로 b.id = ab.id외부 쿼리에서.

db <> 여기에 바이올린
Old sqlfiddle.

이것은 절을 제외하고FROM 표준 SQL 입니다.
실제로 존재하는 열에 관계없이 작동 A하지만 쿼리는 실제 NULL 값과 누락 된 열을 구분할 수 없으므로의 A모든 열 A이 정의 된 경우에만 신뢰할 수 NOT NULL있습니다.

두 테이블에 대해 알고있는 내용 에 따라 여러 가지 가능한 변형이 있습니다.


SQL의 힘! set 절 ( SET (column1) = (a.column)) 에 괄호를 추가하면 Postgres가이를 다른 종류의 업데이트로 취급하고 다음과 같은 오류를 제공합니다.source for a multiple-column UPDATE item must be a sub-SELECT or ROW() expression
Edgar Ortega

26

저는 10 년 이상 IBM DB2 데이터베이스로 작업 해 왔으며 이제 PostgreSQL을 배우려고 노력하고 있습니다.

PostgreSQL 9.3.4에서는 작동하지만 DB2 10.5에서는 작동하지 않습니다.

UPDATE B SET
     COLUMN1 = A.COLUMN1,
     COLUMN2 = A.COLUMN2,
     COLUMN3 = A.COLUMN3
FROM A
WHERE A.ID = B.ID

참고 : 주요 문제점은 DB2에서 지원되지 않고 ANSI SQL에서도 지원되지 않는 FROM 원인입니다.

DB2 10.5에서는 작동하지만 PostgreSQL 9.3.4에서는 작동하지 않습니다.

UPDATE B SET
    (COLUMN1, COLUMN2, COLUMN3) =
               (SELECT COLUMN1, COLUMN2, COLUMN3 FROM A WHERE ID = B.ID)

드디어! PostgreSQL 9.3.4 및 DB2 10.5 모두에서 작동합니다.

UPDATE B SET
     COLUMN1 = (SELECT COLUMN1 FROM A WHERE ID = B.ID),
     COLUMN2 = (SELECT COLUMN2 FROM A WHERE ID = B.ID),
     COLUMN3 = (SELECT COLUMN3 FROM A WHERE ID = B.ID)

3
두 번째 및 세 번째 쿼리는 첫 번째 쿼리와 완전히 동일하지 않습니다. 에서 일치하는 행이 없으면 B첫 번째 문은 아무 작업도 수행하지 않고 (원래 행은 그대로 유지됨) 나머지 두 열은 NULL 값으로 덮어 씁니다.
어윈 Brandstetter

7

이것은 큰 도움이됩니다. 코드

UPDATE tbl_b b
SET   (  column1,   column2,   column3)
    = (a.column1, a.column2, a.column3)
FROM   tbl_a a
WHERE  b.id = 1
AND    a.id = b.id;

완벽하게 작동합니다.

에 대괄호 ""가 필요하다고 언급했습니다.

From "tbl_a" a

작동합니다.


5

반드시 요청한 것은 아니지만 postgres 상속을 사용하면 도움이 될 수 있습니까?

CREATE TABLE A (
    ID            int,
    column1       text,
    column2       text,
    column3       text
);

CREATE TABLE B (
    column4       text
) INHERITS (A);

이렇게하면 B를 업데이트 할 필요가 없습니다.

그러나 모든 세부 사항 을 읽으십시오 .

그렇지 않으면, 당신이 요구하는 것은 좋은 관행으로 간주되지 않습니다.보기와 같은 동적 인 것들은 SELECT * ...권장되지 않습니다. (그런 약간의 편리함은 도움이되는 것보다 더 많은 것을 망칠 수 있기 때문입니다) 그리고 당신이 요청하는 것은 UPDATE ... SET명령에 대해 동등 할 것 입니다.


상속이이 문제를 어떻게 해결할 수 있을지 모르겠습니다. B도 업데이트하는 A에 대한 업데이트 트리거를 추가한다는 의미입니까? A와 B를 항상 동기화하고 싶지는 않습니다. 요청시에만 가능합니다. 그런 경우에는 트리거를 사용할 수 없습니다.
Nir

2
예, 특정 경우에만 상속이 작동하지 않으며이 경우 동적 쿼리 접근 방식을 권장하지 않습니다. (여전히 postgres 절차 적 언어를 사용하여이를 달성하는 방법이 있습니다. 또한 트리거를 사용하려면 트리거를 사용할 수도 있습니다. 예를 들어 트리거가 설정된 경우에만 트리거를 실행하는 것과 같은 동기화 필드를 추가하여).
Unreason

0

이를 위해 동적 SQL을 빌드하고 실행할 수 있지만 실제로는 이상적이지 않습니다.


나는 그것에 대해 생각했다. 나중에 두 테이블에 대한 변경 사항을 준수하도록 쿼리를 만들 수 있다고 생각했지만 동적 SQL은 모든 필드를 지정하고 순방향 호환성을 잊어 버리는 것보다 너무 복잡해 보입니다.
Nir

예, 복잡하지만 나중에 추가되거나 제거되는 열과 호환되어야합니다. 먼저 두 테이블에서 열 이름을 가져 오는 쿼리를 수행 한 다음 열 이름을 일치시킨 다음 일치하는 열 이름을 기반으로 업데이트를 수행하는 동적 SQL을 작성해야합니다. 실제로 재미있는 프로젝트 :)
Daniel Brink

-4

팔로우하기

Update A a, B b, SET a.column1=b.column1 where b.id=1

수정 됨 :-둘 이상의 열 업데이트

Update A a, B b, SET a.column1=b.column1, a.column2=b.column2 where b.id=1

column1, column2 및 column3을 복사하는 방법을 이해하지 못합니다. 그리고 column1을 명시 적으로 언급해야합니다.
Nir

나를 위해 작동하지 않습니다. 다음과 같은 오류가 발생합니다. 오류 : ","근처에서 구문 오류
melbic

1
이 비표준 구문은 UPDATEMySQL에서 작동 하지만 PostgreSQL에는 유효하지 않습니다.
Erwin Brandstetter 2014
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.