SQL 10일차 38, 39, 생각5

수강 날짜 21-08-01

강의명 : 03 INTERSECT 연산
강의명 : 04 EXCEPT 연산
강의명 : 생각대로 SQL-5

INTERSECT

INTERSECT 연산자는 두 개 이상의 SELECT 문들의 결과 집합을 하나의 결과 집합으로 결합한다.

INTERSECT 연산 문법

SELECT
	  COLUMN_1_1
    	, COLUMN_1_2
  FROM
 	  TABLE_NAME_1
INTERSECT
SELECT
	  COLUMN_2_1
    	, COLUMN_2_2
  FROM
  	  TABEL_NAME_2;
  • ORDER BY로 정렬하고자 할 경우 맨 마지막 SELECT문에 ORDER BY절을 사용한다.

  • 다음 그림은 INTECT 연산자에 의해 생산된 최종 결과 세트를 보여준다.
  • 최종 결과 집합은 원 A과 원 B와 교차하는 노란색 영역으로 나타낸다.
  • 즉 집합 A와 B의 교집합을 리턴한다.

UNION과의 차이에 대해 주의할 것

예제를 통해 좀 더 알아보자

employees 테이블

keys 테이블

hipos 테이블

keys 와 hipos테이블에 교집합은 (2, 2002-06-01), (5, 2006-06-01)이 있다.

예제 테이블

select employee_id
  from keys
intersect
select employee_id
  from hipos;

다른 연산과 비교

select k.employee_id 
  from keys k, hipos h
 where k.employee_id = h.employee_id 

select k.employee_id 
  from keys k
 inner join hipos h 
    on k.employee_id = h.employee_id 

똑같은 결과들이다.

INTERSECT쓰는 대신에 INNER JOIN을 더 많이 사용한다.


EXCEPT 연산

EXCEPT 연산자는 맨위에 SELECT문의 결과 집합에서 그 알애에 있는 SELECT문의 결과 집합을 제외한 결과를 리턴한다.

EXCEPT 연산 문법

select 
	  column_1_1
	, column_1-2
  from
    	  table_name_1
except
select
	  column_2_1
	, column_2_2
  from
   	  table_nmae_2;

EXCEPT는 차집합을 표현한다.

EXCEPT 연산 실습
예제에 사용되는 테이블

실습
재고가 존재하는 영화의 필름ID와 영화 제목을 추출하여라

select distinct i.film_id, f.title  
  from inventory i
 inner join film f 
    on f.film_id  = i.film_id 
 order by f.title

그렇다면 재고가 존재하지 않는 영화는 어떻게 추출하는가?

기본 필림 집합 - 재고가 있는 영화 = 재고가 없는 영화!

SELECT film_id, title 
  FROM film 
EXCEPT
SELECT DISTINCT i.film_id, f.title 
  FROM inventory i 
 INNER JOIN film f 
         ON f.film_id = i.film_id
 ORDER BY title 

위의 결과와 다른 값들이 집계된 것을 알 수 있다.


생각대로 -5

문제1번) 영화 배우가, 영화 180분 이상의 길이 의 영화에 출연하거나, 영화의 rating 이 R 인 등급에 해당하는 영화에 출연한 영화 배우에 대해서, 영화 배우 ID 와 (180분이상 / R등급영화)에 대한 Flag 컬럼을 알려주세요.

  • 1) film_actor 테이블와 film 테이블을 이용하세요.
  • 2) union, unionall, intersect, except 중 상황에 맞게 사용해주세요.
  • 3) actor_id 가 동일한 flag 값 이 여러개 나오지 않도록 해주세요.
SELECT DISTINCT actor_id, 'over_length' AS flag
  FROM film_actor fa
 INNER JOIN ( 
	SELECT film_id
	  FROM film
	 WHERE length >=180) f
    ON fa.film_id = f.film_id
UNION ALL 
SELECT DISTINCT actor_id, 'rating_R' AS flag
  FROM film_actor fa
 INNER JOIN ( 
	SELECT film_id
	  FROM film
	 WHERE rating = 'R') f
    ON fa.film_id = f.film_id
ORDER BY actor_id 

유니온을 한다면 중복을 자동으로 제거해서 편하지만 우리가 원치 않는 결과를 초래할 수도 있기 때문에 UNION ALL사용을 권장한다.

문제2번) R등급의 영화에 출연했던 배우이면서, 동시에, Alone Trip의 영화에 출연한 영화배우의 ID 를 확인해주세요.

  • 1) film_actor 테이블와 film 테이블을 이용하세요.
  • 2) union, unionall, intersect, except 중 상황에 맞게 사용해주세요.
SELECT actor_id
  FROM film_actor fa
 INNER JOIN ( 
	SELECT film_id
	  FROM film
	 WHERE rating = 'R') f
    ON fa.film_id = f.film_id
INTERSECT 
SELECT actor_id
  FROM film_actor fa
 INNER JOIN ( 
    SELECT film_id
	  FROM film
	 WHERE title = 'Alone Trip') f
   ON fa.film_id  = f.film_id
 ORDER BY actor_id 

문제3번) G 등급에 해당하는 필름을 찍었으나, 영화를 20편이상 찍지 않은 영화배우의 ID 를 확인해주세요.

  • 1) film_actor 테이블와 film 테이블을 이용하세요.
  • 2) union, unionall, intersect, except 중 상황에 맞게 사용해주세요.
SELECT actor_id
  FROM film_actor fa1
 GROUP BY actor_id
HAVING count(*) < 20
INTERSECT 
SELECT DISTINCT actor_id
  FROM film_actor fa
 INNER JOIN ( 
	SELECT film_id
	  FROM film
	 WHERE rating = 'G') f
    ON fa.film_id = f.film_id
ORDER BY actor_id 
  

문제4번) 필름 중에서, 필름 카테고리가 Action, Animation, Horror 에 해당하지 않는 필름 아이디를 알려주세요.

  • category 테이블을 이용해서 알려주세요.
SELECT fc.film_id 
  FROM film_category fc 
 WHERE fc.category_id IN (
 	SELECT category_id 
 	 FROM category c 
 	WHERE c.name NOT IN ('Action', 'Animation', 'Horror'))
 ORDER BY film_id 

문제5번) Staff 의 id , 이름, 성 에 대한 데이터와 , Customer 의 id, 이름 , 성에 대한 데이터를 하나의 데이터셋의 형태로 보여주세요.

  • 컬럼 구성 : id, 이름 , 성, flag (직원/고객여부) 로 구성해주세요.
SELECT DISTINCT staff_id AS id, first_name, last_name, 'staff' AS flag
  FROM staff s 
 UNION ALL
SELECT DISTINCT customer_id AS id, first_name, last_name, 'customer' AS flag
  FROM customer c
 ORDER BY id

문제6번) 직원과 고객의 이름이 동일한 사람이 혹시 있나요? 있다면, 해당 사람의 이름과 성을 알려주세요.

SELECT first_name, last_name 
  FROM customer c 
INTERSECT 
SELECT first_name, last_name 
  FROM staff s

이름이 동일한 사람이 존재하지 않다는 것을 알 수 있다.

문제7번) 반납이 되지 않은 대여점(store)별 영화 재고 (inventory)와 전체 영화 재고를 같이 구하세요. (union all)

문제가 이해가 되지 않아 정답을 보니 다음을 물어보고 있었다,

반납이 되지 않은 영화 개숫를 대여점별로 집계하고 전체 합계도 같이 표현하라

SELECT null, count(*)
  FROM inventory i
 WHERE inventory_id in(
	SELECT inventory_id 
	  FROM rental r
	 WHERE return_date IS NULL ) 
UNION ALL
SELECT store_id, count(*)
  FROM inventory i
 WHERE inventory_id in(
	SELECT inventory_id 
	  FROM rental r
	 WHERE return_date IS NULL )
 GROUP BY store_id 	 

문제8번) 국가(country)별 도시(city)별 매출액, 국가(country)매출액 소계 그리고 전체 매출액을 구하세요. (union all)

SELECT co.country , ct.city, sum(amount) AS rental_amount
  FROM payment p 
 INNER JOIN customer c ON p.customer_id =c.customer_id 
 INNER JOIN address a ON c.address_id  = a.address_id 
 INNER JOIN city ct ON a.city_id = ct.city_id 
 INNER JOIN country co ON ct.country_id  = co.country_id
 GROUP BY co.country_id, ct.city_id
UNION ALL 
SELECT co.country, NULL , sum(amount) AS rental_amount
  FROM payment p 
 INNER JOIN customer c ON p.customer_id =c.customer_id 
 INNER JOIN address a ON c.address_id  = a.address_id 
 INNER JOIN city ct ON a.city_id = ct.city_id 
 INNER JOIN country co ON ct.country_id  = co.country_id
 GROUP BY co.country_id 
UNION ALL 
SELECT NULL, NULL, sum(amount) AS rental_amount
  FROM payment p

다음과 같이 나온다.

좋은 웹페이지 즐겨찾기