DB (DataBase)

SQL 쿼리문 정리 - Subquery

FDEE 2021. 4. 7. 22:31

 

[ subquery ] - where 문

 

outer query : 바깥의 query를 뜻

inner query, sub query, nested query : 안의 query를 뜻

 

outer query의 attribute 값과 inner query의 colum을 비교한다.

이때 inner query가 outer query 값에 영향을 받을 때 Correlated subquery 라고 부른다.

 

 

 

* in, some, all : outer query의 attribute 와 inner query의 attribute에 해당되는 colum과 비교한다

 

1. in : 포함여부(true, false) 즉 outer query가 inner query에 포함되는 결과만 반환

  즉 intersect와 동일한 결과

 

2. not in : 포함하지 않는 여부(true, false) 즉 outer query가 inner query에 포함되지 않는 결과만 반환

  즉 except와 동일한 결과

 

Q : Find courses offered in Fall 2009 and in Spring 2010

-- 1. intersect 교집합을 통한 결과
(select course_id
from section
where semester = 'Fall' and year = 2009)

intersect

(select course_id
from section
where semester = 'Spring' and year = 2010);
-- 2. in : 포함 여부를 통한 결과
select distinct course_id
from section
where semester = 'Fall' and year = 2009 and course_id in
	(select course_id
	from section
	where semester = 'Spring' and year = 2010);

 

Q : Find courses offered in Fall 2009 but not in Spring 2010

-- 1. except 차집합을 통한 결과
(select course_id
from section
where semester = 'Fall' and year = 2009)

except

(select course_id
from section
where semester = 'Spring' and year = 2010);
-- 2. not in : 비포함 여부를 통한 결과
select distinct course_id
from section
where semester = 'Fall' and year = 2009 and course_id not in
	(select course_id
	from section
	where semester = 'Spring' and year = 2010);

 

Q : Find the total number of (distinct) students who have taken course sections taught by the instructor with ID 10101

-- 1. in을 통한 결과
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');
-- 2. join, using 과 where 조건을 통한 결과
select count(distinct takes.ID)
from takes join teaches using (course_id, sec_id, semester, year)
where teaches.ID = '10101';

 

3. comp + some : outer query 중 inner query 간의 comp를 만족하는 결과를 반환.

  즉 at least one 과 동일한 의미이다.

 

보통 <, > 와 some의 경우 해당 colum의 min값과 비교되는 의미이다.

 

Q : Find names of instructors with salary greater than that of some (at least one) instructor in the Biology department.

-- 1. some을 통한 연산 결과
select name
from instructor
where instructor.salary > some
	(select salary
	from instructor
	where dept_name = 'Biology');
-- 2. as 와 Cartesian product를 통한 결과
select distinct T.name
from instructor as T, instructor as S
where T.salary > S.salary and S.dept_name = 'Biology';

 

4. some 과 in 비교

- = some (r) 는 in (r) 과 동일한 결과이다. : r에 만족하는 값이 있는지 여부이기 때문이다.

- <> some (r) 은 not in (r) 과 완전 다른 결과이다. : r에 만족하지 않는 값이 있는지 여부 / r에 만족하는것이 존재하면 안된다

 

5. comp + all : outer query의 값이 항상 inner query의 값과 comp를 만족하는 결과를 반환.

 

보통 <, >와 all의 경우 해당 colum의 max 값과 비교되는 의미이다.

 

Q : Find the names of all instructors whose salary is greater than the salary of all instructors in the Biology department.

select name, salary
from instructor
where salary > all
	(select salary
	from instructor
	where dept_name = 'Biology');

 

 

6. all 과 in 비교

- <> all (r) 는 not in (r) 과 동일한 결과이다. : r에 만족하는 것이 존재하면 안된다는 뜻.

 

7. exists, not excists : 공집합 여부를 반환.

  exists : 존재하는 경우, 즉 outer query 값을 기준으로 inner query가 특정 comp를 만족하는 결과가 있을 경우를 반환한다.

이때 inner query가 outer query 값에 영향을 받을 때 Correlated subquery 라고 부른다.

 

Q : Find all courses taught in both the Fall 2009 semester and in the Spring 2010 semester

-- exists를 통해 공집합이 아는 경우, 즉 comp에 맞는 값이 있을 경우 결과를 출력
select course_id
from section as S
where semester = 'Fall' and year = 2009 and exists
	(select *
	from section as T
	where semester = 'Spring' and year = 2010
		and S.course_id = T.course_id);

 

Q : Find all students who have taken all courses offered in the Biology department.

-> Biology 과목을 모두 수강한 학생들을 찾아라

 

-> 해당 조건을 만족하는 학생은 수강한 과목들 중 Biology 과목들을 지니고 있다

-> Biology 과목 - 해당 학생의 과목들 = 공집합을 만족한다

 

-> 즉 학생들 중 "Bio - 학생의 과목 = 공집합" 을 만족하는 학생들을 출력하면 된다!

-- 1. not exists 와 except를 통한 집합관계를 통한 결과
select *
from student as S
where not exists ( -- 공집합을 만족하는 학생 S를 찾아 출력하자
	-- 공집합 : Bio 전체과목 - 특정 학생 s가 수강한 과목
	-- 즉 학생 s가 Bio 전체과목을 들은 경우만 공집합이 성립된다
	
	-- Biology 소속 과목들 전체 : 3가지
	(select course_id
	from course
	where dept_name = 'Biology')

	except
	
	-- 학생 s의 수강한 과목들 : S의 학생목록별로 달라진다 (Correlated subquery)
	(select T.course_id
	from takes as T
	where S.id = T.id));
-- 2. Bio 과목수 = (takes의 Bio 과목 중 takes의 id가 학생 id와 동일) 과목수 비교를 통한 결과
select *
from student as S
where (select count(distinct course_id)
	  from course
	  where dept_name = 'Biology')
	  =
	  (select count(distinct T.course_id)
	  from takes as T, course as C
	  where 
	  	S.id = T.id and
	  	T.course_id = C.course_id and
	  	C.dept_name = 'Biology');

 

 

[ subquery ] - from 문

 

where 문에 inner query 와 마찬가지로

from 문에 새로운 relation을 넣을 수 있다

만들어진 새로운 relation에서 where 문에 조건을 추가할 수 있다.

 

다만 일반적으로 from 절의 relation의 경우 Correlated subquery가 될 수 없다.

 

Q : Find the average instructors' salaries of those departments where the average salary is greater than 42000.

select dept_name, avg_salary
from (select dept_name, avg(salary) as avg_salary 
	  from instructor 
	  group by dept_name) as x
where avg_salary > 42000;
-- as 뒤에 새로운 relation 이름과 type을 명시할 수 있다
select dept_name, avg_salary
from (select dept_name, avg(salary)
	 from instructor
	 group by dept_name) as dept_avg(dept_name, avg_salary)
where avg_salary > 42000;

 

Q : Find the instructors's name, salary, dept_name from instructor, and avg_salary where the salary is greater than avg_salary (avg_salary = dept_name의 avg(salary)값)

-- 1. ,를 통한 결합과 where의 조건을 통한 결과
select name, salary, A.dept_name, avg_salary
from instructor as A, 
	(select dept_name, avg(salary) as avg_salary
	from instructor
	group by dept_name) as B
where A.dept_name = B.dept_name and A.salary > B.avg_salary;
-- 2. join 과 using을 통한 결합과 where의 조건을 통한 결과
select name, salary, dept_name, avg_salary
from instructor join
	(select dept_name, avg(salary) as avg_salary
	from instructor
	group by dept_name) as B using (dept_name)
where salary > avg_salary;
-- 3. natural join을 통한 결합, where를 통한 조건 결과
select name, salary dept_name, avg_salary
from instructor natural join 
	(select dept_name, avg(salary) as avg_salary
	 from instructor
	 group by dept_name) as x
where salary > avg_salary;
-- 4. lateral를 통한 correlated 방식
-- , 과 lateral의 where 에서 dept_name을 통하여 결합 후 where의 조건을 통한 결과
select name, salary, dept_name, avg_salary
from instructor as l1, lateral
	(select avg(salary) as avg_salary
	from instructor as l2
	where l1.dept_name = l2.dept_name) as x
where salary > avg_salary;

 

 

 

[ with ] : 임시의 relation 생성

 

1. lateral : 만약 from 절을 correlated subquery로 하고싶을 경우 join 앞에 명시한다.

Q : find the instructors's name, salary, avg_salary (avg_salary = dept_name의 avg(salary)값)

-- lateral 키워드를 사용하여 correlated subquery로 사용이 가능하다.
select name, salary, avg_salary
from instructor l1, lateral
	(select avg(salary) as avg_salary
	from instructor l2
	where l2.dept_name = l1.dept_name) as x;

 

 

2. with : 임시로 새로운 relation을 만든다

새로운 relation을 통해 계속 비교해야 하는경우 with를 통해 만들어 놓고 비교하는 방식으로 사용된다

 

Q : Find all departments with the maximum budget

-- with 를 통해 max_budget relation을 임시로 생성한다
with max_budget(value) as
(select max(budget)
from department)
-- 만들어진 max_budget relation과 결합하여 결과를 구한다
select dept_name
from department, max_budget
where department.budget = max_budget.value;

 

Q : Find all departments where the total salary is greater than the average of the total salary at all departments

-- 1. 각 dept_name 별 합산 relation을 구한다
with dept_total(dept_name, value) as
	(select dept_name, sum(salary)
	from instructor
	group by dept_name),
-- 2. 위의 dept_name 별 평균값을 통해 전체학과의 평균값 relation을 구한다
	dept_total_avg(value) as
	(select avg(value)
	from dept_total)
-- 3. 위에서 만든 dept_name 별 합산, 전체 합산을 통하여 where 조건에 맞게 출력한다
select dept_name, dept_total.value, dept_total_avg.value
from dept_total, dept_total_avg
where dept_total.value > dept_total_avg.value;

 

 

 

 

[ subquery ] - select 문

select 문에서 subquery가 사용되는 경우 attribute 값이 결과로 나오는 subquery 만 가능하다

이 때 반환값이 scalar 값일 경우 scalar subquery 라고 한다

 

 

Q : Find the instructors's counts of each department

select dept_name, (select count(*)
-- 교수수 구하기 : from 교수에서 dept_name이 같은 수를 반환
	from instructor
	where department.dept_name = instructor.dept_name) 
	as num_instructors
from department;

'DB (DataBase)' 카테고리의 다른 글

쿼리문 임시저장소  (0) 2021.04.12
JDBC : Java(eclipse), DB(progresSql) 연결하기  (0) 2021.04.12
SQL 쿼리문 정리  (0) 2021.04.06
SQL 쿼리문 정리 - BASIC  (0) 2021.04.05