Oracle에서 내부 조인이 포함 된 명령문 업데이트


298

MySQL에서 잘 작동하는 쿼리가 있지만 Oracle에서 실행할 때 다음 오류가 발생합니다.

SQL 오류 : ORA-00933 : SQL 명령이 제대로 종료되지 않았습니다.
00933. 00000- "SQL 명령이 제대로 종료되지 않았습니다."

쿼리는 다음과 같습니다.

UPDATE table1
INNER JOIN table2 ON table1.value = table2.DESC
SET table1.value = table2.CODE
WHERE table1.UPDATETYPE='blah';

내 대답을 테스트하기 위해 Oracle에서 table2를 설정하려고 시도했을 때 Oracle은 DESC를 열 이름으로 거부했습니다.
Janek Bogucki 님

죄송합니다. 원래 열 이름을 축약하여 db에서 명확하게 설명하지 않았습니다.
user169743

답변:


412

이 구문은 Oracle에서 유효하지 않습니다. 당신은 이것을 할 수 있습니다 :

UPDATE table1 SET table1.value = (SELECT table2.CODE
                                  FROM table2 
                                  WHERE table1.value = table2.DESC)
WHERE table1.UPDATETYPE='blah'
AND EXISTS (SELECT table2.CODE
            FROM table2 
            WHERE table1.value = table2.DESC);

또는 이 작업을 수행 할 있습니다.

UPDATE 
(SELECT table1.value as OLD, table2.CODE as NEW
 FROM table1
 INNER JOIN table2
 ON table1.value = table2.DESC
 WHERE table1.UPDATETYPE='blah'
) t
SET t.OLD = t.NEW

Oracle에서 인라인보기를 업데이트 할 수 있는지 여부에 따라 다릅니다 (두 번째 명령문의 업데이트 가능 여부는 여기에 나열된 일부 규칙에 따라 다릅니다 ).


5
두 번째 예제를했지만 select의 열 이름에 별칭을 추가 한 다음 SET에서 해당 이름으로 별칭을 참조해야했지만 감사했습니다.
Gustavo Rubio

41
두 번째 예는 실제로 업데이트를 수행하기 전에 SQL을 테스트 할 수 있다는 이점이 있습니다.
Daniel Reis 2018 년

10
두 번째 예는 나를 위해 일했습니다. 나는 깨끗하고 읽을 수 있기 때문에 그 것을 좋아합니다. 성능과 관련하여 둘 사이의 장단점이 무엇인지 모릅니다. 그러나 나는 지금 'cuz에 대해 나쁜 데이터를 수정하기 위해 스크립트를 사용 하여이 문제를 걱정하지 않았습니다.
nemo

5
두 번째는 나를 위해 일했다 :). 오라클은 하나 강하지 만 이상한 동물이다 : /
elrado

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

202

이것을 사용하십시오 :

MERGE
INTO    table1 trg
USING   (
        SELECT  t1.rowid AS rid, t2.code
        FROM    table1 t1
        JOIN    table2 t2
        ON      table1.value = table2.DESC
        WHERE   table1.UPDATETYPE='blah'
        ) src
ON      (trg.rowid = src.rid)
WHEN MATCHED THEN UPDATE
    SET trg.value = code;

2
완벽하게 작동하지만 Oracle은 나에게 말하기 merge into table 1 t등 을 요구했습니다 .
Michael-O

1
파티에 늦었지만 여전히 좋은 실입니다. 알아야 할 것, .. 내가 뭔가를 놓쳤습니까? 마스터 테이블 "table1" USING에서 table1의 별명은 t1입니다. t2로 별칭이 지정된 Table2이지만 ON에서 참조는 다음과 같습니다. 외부 테이블 1-t1 아님-외부 테이블 또는 유형에 대한 참조입니까? 표 2? t2가 아닙니까? Je suis는 혼란 스러웠다. 더 나은 별칭의 팬 ...
Marc

키 (trg.rowid 또는 src.rid)에 중복 된 항목이 하나 있으면이 절에서 오류가 발생합니다. ora-30926.ora-code.com
Henrique

@Marc에서는 ON, trg상기 마스터 테이블에 대한 별명이다 table1(당신의 논리에 의해 "외부"테이블)을 src참조합니다 USING(당신의 논리에 의해 "내부 테이블") 그룹. 그러나 그렇습니다. 아마도 더 잘 참조되었을 수는 있지만 따랐습니다.
vapcguy

1
@ supernova : tony의 답변은 인라인보기를 업데이트합니다. 경우에 따라 작동 할 수 있지만 뷰는 "키 보존"되어야합니다 (결합 된 모든 테이블은 기본 키 또는 다른 고유 필드 집합에서 동일하게 조인되어야 함). 이렇게하면 목표 테이블의 모든 레코드가 결과 행 집합에서 최대 하나의 레코드에 기여하므로 목표 테이블의 모든 레코드가 최대 한 번 업데이트됩니다.
Quassnoi

25

MERGEwith WHERE절 :

MERGE into table1
USING table2
ON (table1.id = table2.id)
WHEN MATCHED THEN UPDATE SET table1.startdate = table2.start_date
WHERE table1.startdate > table2.start_date;

WHERE절에서 참조 된 열을 ON업데이트 할 수 없으므로 절이 필요합니다 .


이 버전은 틀림없이 깨끗하지만이 구문을 사용하여 변경되지 않은 행에 대해 업데이트 트리거를 트리거하는 것을 피할 수있는 방법이 없기 때문에 트리거 친화적이지 않습니다. ( 변경된 행에 트리거가 필요하다고 가정합니다 .)
sf_jeff

14
 UPDATE ( SELECT t1.value, t2.CODE
          FROM table1 t1
          INNER JOIN table2 t2 ON t1.Value = t2.DESC
          WHERE t1.UPDATETYPE='blah')
 SET t1.Value= t2.CODE

11

위의 답변 중 일부를 사용하지 마십시오.

일부는 중첩 된 SELECT의 사용을 제안하지만 그렇게하지 마십시오. 매우 느립니다. 업데이트 할 레코드가 많으면 join을 사용하십시오.

update (select bonus 
        from employee_bonus b 
        inner join employees e on b.employee_id = e.employee_id 
        where e.bonus_eligible = 'N') t
set t.bonus = 0;

자세한 내용은이 링크를 참조하십시오. http://geekswithblogs.net/WillSmith/archive/2008/06/18/oracle-update-with-join-again.aspx .

또한 결합하는 모든 테이블에 기본 키가 있는지 확인하십시오.


7

여기 에 표시된 것처럼 Tony Andrews가 제안한 첫 번째 솔루션의 일반적인 구문은 다음과 같습니다.

update some_table s
set   (s.col1, s.col2) = (select x.col1, x.col2
                          from   other_table x
                          where  x.key_value = s.key_value
                         )
where exists             (select 1
                          from   other_table x
                          where  x.key_value = s.key_value
                         )

하나 이상의 필드를 업데이트하려는 경우 특히 흥미로운 것으로 생각됩니다.


이것은 나를 위해 작동하지 않습니다. 전체 테이블을 업데이트합니다.
Natassia Tavares

3

이 다음 구문은 저에게 효과적입니다.

UPDATE
(SELECT A.utl_id,
    b.utl1_id
    FROM trb_pi_joint A
    JOIN trb_tpr B
    ON A.tp_id=B.tp_id Where A.pij_type=2 and a.utl_id is null
)
SET utl_id=utl1_id;

@JimGarrison이 답을 다시 편집하여 downvote ...를 제거하십시오.이 구문을 사용하려고하는데 테이블을 업데이트하지 않았습니다. 나는 왜-내 SETREPLACE을하고 열에서 특정 문자열을 비우려고했습니다-Oracle은 ''null로 취급 하고이 필드는 null 수 없습니다. 구문이 실제 테이블 대신 임시 테이블을 업데이트하는 것이라고 생각했지만 잘못되었습니다.
vapcguy

2

table2에 desc 대신 description 을 사용하면

update
  table1
set
  value = (select code from table2 where description = table1.value)
where
  exists (select 1 from table2 where description = table1.value)
  and
  table1.updatetype = 'blah'
;

왜 u가 table2에 대해 두 개의 개별 쿼리를 실행
하려고합니까

2

훌륭한 오라클 작동

merge into table1 t1
using (select * from table2) t2
on (t1.empid = t2.empid)
when matched then update set t1.salary = t2.salary

끝에 쉼표를 추가하여 여러 속성을 설정할 수 있습니다. 내가 할 필요 t1.First_Name = t2.FirstName, t1.Last_Name = t2.LastName은 "사용자 이름"열 (에 일치 한 후 테이블에 t1.UserName = t2.UserName테이블에서 자신의 이름을 검색) (사용자 정보라고합니다 select * from UserInfo) t2). 데이터베이스는 테이블에 FirstName과 LastName을 직접 배치하는 대신 UserName을 UserInfo의 기본 키로 사용하는 곳이었습니다. 이것은 고정되었습니다!
vapcguy

이 답변은 5 년 전에 Quassnoi가 이미 제공 한 답변에는 아무 것도 추가하지 않습니다.
Forage

0
UPDATE table1 t1
SET t1.value = 
    (select t2.CODE from table2 t2 
     where t1.value = t2.DESC) 
WHERE t1.UPDATETYPE='blah';

0
UPDATE IP_ADMISSION_REQUEST ip1
SET IP1.WRIST_BAND_PRINT_STATUS=0
WHERE IP1.IP_ADM_REQ_ID        =
  (SELECT IP.IP_ADM_REQ_ID
  FROM IP_ADMISSION_REQUEST ip
  INNER JOIN VISIT v
  ON ip.ip_visit_id=v.visit_id
  AND v.pat_id     =3702
  ); `enter code here`

0

완전성의 문제와 마찬가지로 오라클과 이야기하고 있기 때문에 다음과 같이 할 수도 있습니다.

declare
begin
  for sel in (
    select table2.code, table2.desc
    from table1
    join table2 on table1.value = table2.desc
    where table1.updatetype = 'blah'
  ) loop
    update table1 
    set table1.value = sel.code
    where table1.updatetype = 'blah' and table1.value = sel.desc;    
  end loop;
end;
/

1
이것은 할 수 있지만 가능한 가장 느린 방법입니다.
APC

-1
UPDATE (SELECT T.FIELD A, S.FIELD B
FROM TABLE_T T INNER JOIN TABLE_S S
ON T.ID = S.ID)
SET B = A;

A와 B는 별칭 필드이므로 테이블을 가리킬 필요가 없습니다.


1
안녕 댄 당신은 이미 매우 좋은 답변을 가지고 꽤 오래된 질문에 게시하고 있습니다. 질문이 다른 솔루션보다 선호되는 경우 설명 할 수 있습니까?
Noel Widmer

1
물론 테이블 이름 (table1.B = table2.A)을 가리켜 b = a가 작성된 대답을 보았지만 테이블을 가리킬 필요는 없습니다.
Dan Anderson

실제로 뷰에서 필드를 업데이트하여 테이블에 매핑합니다. 내부 뷰의 별칭이 h 인 경우 "자체 문서화"버전은 "set hb = ha"입니다.
sf_jeff

-4
update table1  a 
   set a.col1='Y' 
 where exists(select 1 
                from table2 b
               where a.col1=b.col1 
                 and a.col2=b.col2
             )
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.