이번에는 서브쿼리의 일종인 '상관 서브쿼리'를 EXISITS 술어로 조합시켜 서브쿼리를 사용하는 방법에 관해 알아보겠습니다. EXISTS 술어를 사용하면 서브쿼리가 반환하는 결괏값이 있는지를 조사할 수 있습니다. 특히 EXISTS를 사용하는 경우에는 서브쿼리가 반드시 스칼라 값을 반환할 필요는 없습니다. EXISTS는 단지 반환된 행이 있는지를 확인해보고 값이 있으면 참, 없으면 거짓을 반환하기 때문입니다.
EXISTS
서브쿼리를 사용해 검색할 때 '데이터가 존재하는지 아닌지' 판별하기 위해 조건을 지정할때 EXISTS 술어를 사용해 조사할 수 있습니다. EXISTS의 용법을 자세히 설명하기 위해 다음과 같이 두 개의 샘플 테이블을 사용하겠습니다.
SELECT * FROM sample551;
SELECT * FROM sample552;
sampel551에는 1에서 5까지의 데이터가 저장되어있고 sample552에는 3과5가 저장되어 있습니다. 여기서 sample551의 a열은 문자열이지만 모두 NULL로 되어있습니다. 이 a열을 sample552에 no열의 값과 같은 행이 있다면 '있음'이라는 값으로, 행이 없으면 '없음'이라는 값으로 갱신하겠습니다.
UPDATE sample551 SET a = '있음'
WHERE EXISTS (SELECT * FROM sample552 WHERE no2 = no);
WHERE 구 뒤에 EXISTS로 서브쿼리를 반환해준 모습입니다. 서브쿼리 부분이 UPDATE의 WHERE구로 행을 검색할 때마다 차례로 실행되는 느낌입니다. 이때 no가 3과 5일 때만 서브쿼리가 행을 반환합니다. EXISTS 술어에 서브쿼리를 지정하면 서브쿼리가 행을 반환할 경우에 참을 돌려줍니다. 결과가 한 줄이라도 참이 됩니다. 반환되는 행이 없을 경우에는 거짓이 됩니다.
NOT EXISTS
'없음'의 경우, 행이 존재하지 않는 상태가 참이 되므로 이때는 NOT EXISTS를 사용합니다.
UPDATE sample551 SET a = '없음'
WHERE NOT EXISTS (SELECT * FROM sample552 WHERE no2 = no);
잘 갱신된 것을 볼 수있습니다.
상관 서브쿼리
UPDATE 명령(부모)에서 WHERE 구에 괄호로 묶은 부분이 서브쿼리(자식)이 됩니다 부모 명령에서는 sample551을 갱신하고 자식인 서브쿼리에서는 sample552의 no2 열 값이 부모의 no 열 값과 일치하는 행을 검색합니다. 이처럼 부모 명령과 자식 서브쿼리가 특정 관계를 맺는 것을 '상관 서브쿼리'라 부릅니다.
그냥 서브쿼리는 단독쿼리로 실행할 수 있습니다. 하지만 상관 서브쿼리에서는 부모 명령과 연관되어 처리되기 때문에 서브쿼리 부분만 따로 떼어내어 실행시킬 수 없습니다.
테이블명 붙이기
위에 예시는 두 테이블의 비교하려는 열의 이름이 다르기 때문에 WHERE no2 = no 라 지정할 수 있었습니다. 근데 만약 두 열의 이름이 같다면 어떻게 될까요? 역시 잘 동작하지 않습니다. 그래서 만약 위의 두 테이블의 이름이 no로 서로 같았다고 하면 WHERE sample551.no = sample552.no 이렇게 열 앞에 테이블명을 붙여주면 됩니다.
IN
스칼라 값끼리 비교할 때는 = 연산자를 사용합니다. 다만 집합을 비교할 때는 사용할 수 없습니다. IN을 사용하면 집합 안의 값이 존재하는 지를 조사할 수 있습니다.
sample552에는 3과 5라는 값이 존재합니다. sample552와 같은 열을 선택할때 서브쿼리를 사용하지 않고 WHERE 구로 간단하게 처리하려면 'WHERE no = 3 OR no = 5' 이렇게 지정해야 할 것입니다. 하지만 집합을 사용할 경우 더 간단합니다.
SELECT * FROM sample551
WHERE no IN (3,5);
또한, 집합 부분은 서브쿼리로도 지정할 수 있습니다.
SELECT * FROM sample551
WHERE no IN (SELECT * FROM sample552);
이 같은 경우 또한 서브쿼리는 스칼라 서브쿼리가 될 필요는 없습니다.
참고자료 : <SQL 첫걸음(아사이 아츠시)>