Nested Subquery
상위 문서: SQL
개요
Subquery란, 다른 쿼리 안에 포함된 select-from-where 쿼리를 의미한다. 예를 들면 아래와 같다.
select name
from instructor
where dept_name = (select dept_name from department where building = 'Watson');
일반적인 SQL의 쿼리는 다음과 같은 형태를 가진다.
select A1, A2, ..., An
from r1, r2, ..., rm
where P
이때, subquery는 select, from, where 절에서 사용될 수 있다.
From 절에서의 Subquery
ri 자리에 하나의 서브쿼리를 넣을 수 있으며, 마치 테이블처럼 다룰 수 있다. 이때 subquery에는 as 키워드를 사용하여 별칭 주는 것이 일반적이다. 이는 아래와 같이 사용된다.
select *
from (select * from instructor where salary > 50000) as high_paid;
Where 절에서의 Subquery
P 자리에 조건식을 쓸 수 있는데, 그 조건식 안에 서브쿼리를 넣을 수 있다. 이때 조건식은 다음과 같이 작성된다.
B <operation> (subquery)
이때 B는 속성에 해당하며, <operation>은 비교 연산 (=, >, <, in, exists 등)에 해당한다. 이를 바탕으로 where 절에서 subquery는 아래와 같이 사용된다.
select name
from instructor
where salary > (select avg(salary) from instructor);
Select 절에서의 Subquery
Ai 자리에 단일 값을 반환하는 서브쿼리를 넣을 수 있다. 이는 아래와 같이 사용된다.
select name, (select count(*) from teaches where teaches.ID = instructor.ID) as um_courses
from instructor;
Set Membership
SQL은 튜플(값)이 어떤 relation(또는 집합)에 속하는지 여부를 검사하는 기능인 집합 멤버십(set membership)을 제공한다. in 연결자는 집합 멤버십을 테스트하는데 사용되며, 이 집합은 select 절이 생성한 값들의 모음이다. not in 연결자는 집합에 속하지 않음을 테스트하는 데 사용된다. 예를 들어, “2017년 가을 학기와 2018년 봄 학기 두 학기 모두에 개설된 과목들을 찾아라.”과 같은 쿼리를 두 집합의 교집합을 이용해 작성하였다. 하지만 이와는 in 연결자를 사용하는 방식으로도 같은 질의를 표현할 수 있다. 즉, 2017년 가을 학기에 개설된 과목 중, 2018년 봄 학기에 개설된 과목들의 집합에 속하는 과목들만 찾는 방식이다. 이는 다음과 같이 나타내어진다.
select distinct course_id
from section
where semester = 'Fall' and year = 2017 and
course_id in (select course_id
from section
where semester = 'Spring' and year = 2018);
이때 교집합 연산은 기본적으로 중복을 제거하므로, 교집합을 사용한 것과 동일한 결과를 얻기 위해서는 이 질의에서도 distinct 키워드를 사용해야 한다.
in 연산자와 비슷하게, not in 연산자도 유사한 방식으로 사용할 수 있다. 예를 들어 "2017년 가을 학기에는 개설되었지만, 2018년 봄 학기에는 개설되지 않은 과목들을 찾기"와 같은 질의를 생각해보자. 우리는 이 질의를 앞에서 except 연산을 사용하여 표현했었지만, 이 질의를 not in을 사용하여 표현하면 다음과 같다:
select distinct course_id
from section
where semester = 'Fall' and year = 2017 and
course_id not in (select course_id
from section
where semester = 'Spring' and year = 2018);
또한, in 및 not in 연산자는 열거형 집합(enumerated sets) 에도 사용할 수 있다. 예를 들어, 이름이 “Mozart”도 아니고 “Einstein”도 아닌 교수들을 찾는 쿼리는 다음과 같다:
select distinct name
from instructor
where name not in ('Mozart', 'Einstein');
앞선 예제들에서는 속성이 하나인 릴레이션(one-attribute relation)에 대해서만 멤버십을 테스트했다. 하지만, SQL에서는 임의의 relation에 대해 멤버십을 테스트하는 것도 가능하다. 예를 들어, “ID가 110011인 교수가 가르친 과목 섹션을 수강한 학생들의 (중복 없는) 총 인원 수를 구하라.”와 같은 쿼리는 아래와 같이 나타내어진다.
select count(distinct ID)
from takes
where (course_id, sec_id, semester, year) in
(select course_id, sec_id, semester, year
from teaches
where teaches.ID = '10101');