Oracle SQL : 다른 테이블의 데이터로 테이블 업데이트


251

1 번 테이블:

id    name    desc
-----------------------
1     a       abc
2     b       def
3     c       adf

표 2 :

id    name    desc
-----------------------
1     x       123
2     y       345

오라클 SQL에서 어떻게 실행합니까 SQL 업데이트 표 2의와 표 1을 업데이트 할 수 있습니다 쿼리 namedesc같은를 사용하여 id? 그래서 내가 얻을 최종 결과는

1 번 테이블:

id    name    desc
-----------------------
1     x       123
2     y       345
3     c       adf

하나의 테이블을 다른 테이블의 데이터로 업데이트 하지만 특히 Oracle SQL에 대한 질문에서 문제가 발생 합니다.



다른 질문으로 돌아가서 해당 답변을 수락하지 말고 구체적으로 Oracle PLSQL 구문이 필요하다고 명시해야합니다.
p.campbell

3
@ p.campbell, 그건 내 질문이 아니다 ...
Muhd

1
아 알 겠어요 따라서 질문 본문을 복사하여 붙여 넣었지만 Oracle 비트를 포함하도록 수정했습니다.
p.campbell

2
네. "desc"가 예약어이기 때문에 이것은 아마도 가장 좋은 예가 아닐 것입니다.
Muhd

답변:


512

이를 상관 업데이트라고합니다

UPDATE table1 t1
   SET (name, desc) = (SELECT t2.name, t2.desc
                         FROM table2 t2
                        WHERE t1.id = t2.id)
 WHERE EXISTS (
    SELECT 1
      FROM table2 t2
     WHERE t1.id = t2.id )

조인 결과 키 보존보기가 있다고 가정하면

UPDATE (SELECT t1.id, 
               t1.name name1,
               t1.desc desc1,
               t2.name name2,
               t2.desc desc2
          FROM table1 t1,
               table2 t2
         WHERE t1.id = t2.id)
   SET name1 = name2,
       desc1 = desc2

8
첫 번째 코드 예제에서 : 정확한 결과를 위해 외부 WHERE 절이 필요합니까? 아니면 쿼리 속도를 높이기 위해서만 사용합니까?
Mathias Bader

41
@totoro-첫 번째 예에서는에 일치하는 행이없는 경우 WHERE EXISTS행을 업데이트하지 못하게합니다 . 이를 사용하지 않으면에있는 모든 행 이 업데이트되고에 일치하는 행이없는 경우 값이 설정됩니다 . 그것은 일반적으로 원하는 일이 아니므 로 일반적으로 필요합니다. t1t2t1NULLt2WHERE EXISTS
저스틴 동굴

3
SELECT ... FROM t2 필수 행이 고유 해야 한다는 점을 추가하는 것이 좋습니다. 따라서 고유 키를 구성하는 모든 필드를 선택해야합니다. 고유하지 않은 기본 키로는 충분하지 않습니다. 고유성이 없으면 @PaulKarr의 루프 와 같이 줄어 듭니다 . 고유 한 상관 관계가없는 경우 각 소스 행에 대해 둘 이상의 대상 행이 업데이트 될 수 있습니다.
Andrew Leach

2
업데이트 가능한 조인을위한 키 보존 요구 사항에 대한 설명 : asktom.oracle.com/pls/asktom/…
Vadzim

1
@RachitSharma-하위 쿼리 (의 쿼리 table2)가 하나 이상의 table1값에 대해 여러 행을 반환 하고 Oracle이 어떤 값을 사용할지 알지 못함을 의미합니다. 일반적으로 하위 쿼리를 수정하여 단일 고유 행을 반환해야 함을 의미합니다.
저스틴 동굴

132

이 시도:

MERGE INTO table1 t1
USING
(
-- For more complicated queries you can use WITH clause here
SELECT * FROM table2
)t2
ON(t1.id = t2.id)
WHEN MATCHED THEN UPDATE SET
t1.name = t2.name,
t1.desc = t2.desc;

4
실제로 매우 빠르게 115,577 개의 행이 15,5 초에 병합되었습니다.
jefissu

3
2015 년 이후 에이 질문을 방문한 모든 사람들 이이 답변을 알기를 바랍니다. 참고이는 경우 작동 table1table2같은 테이블이며, 단지의 관리 걸릴 ONpart의와 WHERE에 대한 -clause을 SELECT의 -statement table2!
sjngm

1
다른 병합을 수행해야 할 때마다 영감을 얻기 위해이 답변으로 계속 돌아옵니다. 나는 그것을 인쇄하여 내 벽에 액자로 만들 수있다
arnehehe

매력처럼 작동합니다! 고마워!
davidwillianx

테이블 2에서 고유 ID, FIELD1, FIELD1을 선택하십시오. ID가 NULL이 아닌 경우
Joseph Poirier

17

시험

UPDATE Table1 T1 SET
T1.name = (SELECT T2.name FROM Table2 T2 WHERE T2.id = T1.id),
T1.desc = (SELECT T2.desc FROM Table2 T2 WHERE T2.id = T1.id)
WHERE T1.id IN (SELECT T2.id FROM Table2 T2 WHERE T2.id = T1.id);

4
이것의 단점은 SELECT 문이 3 번 반복된다는 것입니다. 복잡한 예에서 거래 차단기가 될 수 있습니다.
David Balažic

9
Update table set column = (select...)

set은 1 값만 필요하기 때문에 나를 위해 일한 적이 없습니다-SQL 오류 : ORA-01427 : 단일 행 하위 쿼리가 둘 이상의 행을 반환합니다.

해결책은 다음과 같습니다.

BEGIN
For i in (select id, name, desc from table1) 
LOOP
Update table2 set name = i.name, desc = i.desc where id = i.id;
END LOOP;
END;

그것이 SQLDeveloper 워크 시트에서 정확하게 실행하는 방법입니다. 그들은 느리다고 말하지만 그것은이 경우에 나를 위해 일한 유일한 솔루션입니다.


누군가 이것이 평판에 -2가 필요한 이유를 설명해 주시겠습니까? LOL.
Pau Karr

13
나는 속도를 낮추지 않았지만 좋은 해결책은 아닙니다. 첫째 : subselect가 여러 값을 리턴하는 경우 for 루프는 일부 / 모든 레코드 (정리되지 않은)에 대해 table2의 이름을 여러 번 겹쳐 씁니다. 둘째 : order by 절이 없으므로 예기치 않은 방식으로 발생합니다 (즉, 정렬되지 않은 데이터의 마지막 값이 승리합니다). 셋째 : 속도가 훨씬 느려집니다. for 루프의 결과가 의도되었다고 가정하면, 원래의 하위 선택은 각 레코드에 대해 하나의 값만 반환하도록 제어 된 방식으로 다시 작성되었을 수 있습니다. 가장 간단한 방법은 (select min (name) ...)
Alternator

이것은 내가 필요한 것입니다. 감사합니다 (+1)
Robert Hyatt

3
하위 쿼리에서 여러 값을 얻는 경우 쿼리를 다시 생각하고 MIN, MAX와 함께 DISTINCT 또는 GROUP BY를 사용할 수 있습니다. 그냥 생각이야
프랜시스

간단히 말해 : 전혀 피할 수 있다면 절대 T-SQL 문에 LOOP를 사용하지 마십시오. 개인적으로 다른 솔루션이없는 시간의 0.001 %가 아니었다면 T-SQL에서 사용할 수있는 기능조차도 생각하지 않습니다. T-SQL은 세트 기반으로 설계되었으므로 전체 데이터 세트에서 전체적으로 작동합니다. 데이터를 라인 단위로 작업하는 데 사용해서는 안됩니다.
Ray K.

8

다음은 조인을 위해 여러 키를 허용하는 'in'절을 사용하는 것이 더 나은 답변 인 것 같습니다 .

update fp_active set STATE='E', 
   LAST_DATE_MAJ = sysdate where (client,code) in (select (client,code) from fp_detail
  where valid = 1) ...

쇠고기는 'in'이전의 where 절에서 괄호 안의 키로 사용하려는 열을 가지며 괄호 안에 동일한 열 이름을 가진 select 문이 있습니다. where ( column1, column2 ) in ( "set I want"테이블에서 select ( column1, column2 ) );


링크가 만료되었습니다. ( 404)
Dumbo

-3

테이블 t1과 백업 t2에 많은 열이있는 경우 여기에 간단한 방법이 있습니다.

또한 관련 문제는 일부 열만 수정되었고 많은 행에 이러한 열을 편집하지 않았기 때문에 기본적으로 전체 테이블의 백업에서 열의 하위 집합을 복원하려고했습니다. 모든 행을 복원하려면 where 절을 건너 뛰십시오.

물론 가장 간단한 방법은 선택하여 삭제하고 삽입하는 것이지만 필자의 경우 업데이트 만 가능한 솔루션이 필요했습니다.

트릭은 중복 열 이름을 가진 테이블 쌍에서 *를 선택하면 두 번째 테이블 이름이 _1이라는 것입니다. 그래서 내가 생각해 낸 것은 다음과 같습니다.

  update (
    select * from t1 join t2 on t2.id = t1.id
    where id in (
      select id from (
        select id, col1, col2, ... from t2
        minus select id, col1, col2, ... from t1
      )
    )
  ) set col1=col1_1, col2=col2_1, ...

Oracle 11g에서는 작동하지 않습니다. 이 방법의 실제 예를 만들 수 있습니까?
Jon Heller

-3
BEGIN
For i in (select id, name, desc from table2) 
LOOP
Update table1 set name = i.name, desc = i.desc where id = i.id and (name is null or desc is null);
END LOOP;
END;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.