SQL - UNION / JOIN / Subquery

허재정·2024년 3월 19일

SQL

목록 보기
5/7

1. UNION - 수직결합

  • 여러 개의 SQL문을 합쳐서 하나의 SQL문으로 만들어 줌
  • 각 SQL문의 컬럼의 개수가 동일해야 오류 생기지 않음

(1) UNION : 중복값 제거 후 검색 반환
(2) UNION ALL : 중복된 값을 포함해 모두 반환

    SELECT column1, column2, ... FROM table_A;
    UNION | UNION ALL
    SELECT column1, column2, ... FROM table_B;

(예제)
(1) 성별이 여자인 데이터를 검색하는 쿼리와
소속사가 YG엔터테이먼트인 데이터를 검색하는 쿼리를 UNION으로 실행

SELECT name, sex, agency FROM celeb WHERE sex = "f"
UNION ALL
SELECT name, sex, agency FROM celeb WHERE agency = "YG엔터테인먼트";

(2) 가수가 직업인 연예인의 이름, 직업을 검색하는 쿼리와,
1980년대에 태어난 연예인의 이름, 생년월일, 나이를 검색하는 쿼리를 UNION으로 실행

  • 이 경우 컬럼 개수가 달라서 오류 발생
SELECT name, job_title FROM celeb WHERE job_title LIKE "%가수%"
UNION
SELECT name, birthday, age FROM celeb WHERE birthday BETWEEN '1980-01-01' AND '1989-12-31'; 

2. JOIN - 수평결합

  • 두 개 이상의 테이블을 특정 컬럼 기준으로 결합하는 명령어
  • INNER JOIN / FULL OUTER / LEFT JOIN / RIGHT JOIN
  • snl_show 테이블 이용 (ID SEASON EPISODE BROADCAST_DATE HOST)

(1) INNER JOIN
두 개의 테이블에서 공통된 요소들을 통합해 결합하는 조인 방식. 일종의 교집합
ON : 조인의 기준. 해당 컬럼의 값이 같을 때 조인

SELECT tableA.column1, tableA.column2, ..., tableB.column1, 		tableB.column2, ...
FROM tableA
INNER JOIN tableB
ON tableA.column_name = tableB.column_name WHERE condition;

(예제)
(1) snl_show에 호스트로 출연한 셀럽을 기준으로 celeb Table과 snl_show Table을 INNER JOIN

SELECT celeb.id, celeb.name, snl_show.id, snl_show.host
FROM celeb INNER JOIN snl_show
ON celeb.name = snl_show.host;

(2) LEFT JOIN
두 개 테이블에서 공통 영역 포함하고 왼쪽 테이블에만 있는 다른 데이터도 포함한 조인 방식

SELECT tableA.column1, tableA.column2, ..., tableB.column1, tableB.column2, 
FROM tableA       # 왼쪽 table
LEFT JOIN tableB  # 오른쪽 table
ON tableA.column_name = tableB.column_name WHERE condition;

(예제)
(1) snl_show에 호스트로 출연한 셀럽을 기준으로 celeb Table과 snl_show Table을 LEFT JOIN

SELECT celeb.id, celeb.name, snl_show.id, snl_show.host
FROM celeb 
LEFT JOIN snl_show
ON celeb.name = snl_show.host;

(2) RIGHT JOIN
두 개 테이블에서 공통 영역 포함하고 오른쪽 테이블에만 있는 다른 데이터도 포함한 조인 방식

SELECT tableA.column1, tableA.column2, ..., tableB.column1, tableB.column2,  FROM tableA
RIGHT JOIN tableB
ON tableA.column_name = tableB.column_name WHERE condition;

(예제)
(1) snl_show에 호스트로 출연한 셀럽을 기준으로 celeb Table과 snl_show Table을 RIGHT JOIN

SELECT celeb.id, celeb.name, snl_show.id, snl_show.host
FROM celeb
RIGHT JOIN snl_show
ON celeb.name = snl_show.host;

(3) FULL OUTER JOIN

  • 두 개 테이블에서 공통 영역 포함하고 양쪽 테이블의 다른 영역도 모두 포함시키는 조인 방식 (MySQL 에서 지원하지 않아서 FULL OUTER JOIN 과 같은 결과를 내는 다른 방식)
SELECT tableA.column1, tableA.column2, ..., tableB.column1, tableB.column2, 
FROM tableA FULL OUTER JOIN tableB
ON tableA.column_name = tableB.column_name WHERE condition;

(예제)
(1) snl_show에 호스트로 출연한 셀럽을 기준으로 celeb Table과 snl_show Table을 FULL OUTER JOIN

SELECT celeb.id, celeb.name, snl_show.id, snl_show.host
FROM celeb LEFT JOIN snl_show ON celeb.name = snl_show.host
UNION
SELECT celeb.id, celeb.name, snl_show.id, snl_show.host
FROM celeb RIGHT JOIN snl_show ON celeb.name = snl_show.host;

(4) SELF JOIN

  • INNER JOIN과 같은 결과를 도출하는 조인 방식. 조인되는 테이블 간에 공통된 데이터를 가져 옴
SELECT tableA.column1, tableA.column2, ..., tableB.column1, tableB.column2, FROM tableA, tableB, ...
WHERE condition;  # WHERE 절에 결합의 기준을 명시

(예제)
(1) celeb Table의 연예인 중 snl_show에 host로 출연했고
영화배우는 아니면서 YG엔터테이먼트 소속이거나 40세 이상이면서 YG엔터테이먼트 소속이 아닌 연예인의 이름과 나이, 직업, 소속사, 시즌, 에피소드 정보를 검색

SELECT celeb.name, celeb.age, celeb.job_title, celeb.agency, snl_show.episode
FROM celeb, snl_show
WHERE celeb.name = snl_show.host AND ((job_title NOT LIKE "%영화배우%" AND agency!="YG엔터테인먼트") OR (age >= 40 AND agency !="YG엔터테인먼트"));

====================================================================

3. SQL Subquery

  • 하나의 SQL문 안에 포함되어 있는 또 다른 SQL문
  • 메인 쿼리가 서브쿼리 포함
  • 주의사항 : 서브쿼리는 괄호로 묶어 사용 / 단일 행 혹은 복수 행 비교연산자와 함께 사용 가능 / 서브쿼리에서는 ORDER BY 사용할 수 없음

(1) Scalar Subquery
- SELECT 절에 사용
- 결과는 하나의 컬럼

```
SELECT column1, (SELECT column2 FROM table2_name WHERE condition)
FROM table1_name WHERE condition;
```

(예제)
(1) 서울은평경찰서의 강도 검거 건수와 서울시 경찰서 전체의 평균 강도 검거 건수를 조회

	SELECT case_number 은평경찰서 강도검거건수, (SELECT AVG(case_number) FROM crime_status WHERE crime_type LIKE '강도' AND status_type LIKE '검거') 서울시 경찰서 검거 평균
 FROM crime_status
 WHERE police_station = "은평" AND crime_type = "강도" AND status_type = "검거";

(2) Inline View
- FROM 절에 사용
- 메인 쿼리에서는 인라인뷰에서 조회한 컬럼만 사용 가능

```
SELECT a.column_name, b.column_name, ...
FROM table1_name a, (SELECT column1, column2, ... FROM table2_name) b
WHERE condition;
```
(예제) 
(1) 경찰서 별로 가장 많이 발생한 범죄 건수와 범죄 유형을 조회
```
SELECT c.police_station, c.crime_type, c.case_number
FROM crime_status c, (SELECT police_station, MAX(case_number) count
					  FROM crime_status
                      WHERE status_type = "발생"
                      GROUP BY police_station) m
WHERE c.police_station = m.police_station AND c.case_number = m.count
```

(3) Nested Subquery
- WHERE 절에서 사용
((1)) (SINGLE ROW) : 하나의 행 검색하는 서브쿼리 (서브쿼리가 비교연산자와 사용하는 경우) 괄호가 없거나 한 개 이상의 결과값 가지는 경우 에러 발생

		```
		SELECT column_names,... 
        FROM table_name
		WHERE column_name = (SELECT column_name FROM table_name WHERE 				condition)
		ORDER BY column_names;
		```
        (예제)
        (1) SNL에 출연한 연예인 중 id가 1인 연예인
        ```
		SELECT name FROM celeb WHERE name = (SELECT host FROM snl_show WHERE id=1);
		```
((2)) Multiple Row
	  - 하나 이상의 행을 검색하는 서브쿼리
      - IN : 서브쿼리 결과 중 포함되는 경우
      ```
	  SELECT column_names,... 
      FROM table_name
	  WHERE column_name IN (SELECT column_name FROM table_name WHERE condition)
	  ORDER BY column_names;
	  ```
      (예제)
      (1) SNL에 출연한 영화배우를 조회
      ```
	  SELECT host 
      FROM snl_show
      WHERE host IN (SELECT name FROM celeb WHERE job_title LIKE '%영화배우%';
	  ```
      - EXISTS :  서브쿼리 결과에 값이 있으면 True 반환
      ```
	  SELECT column_names,... 
      FROM table_name
	  WHERE EXISTS (SELECT column_name 
                    FROM table_name 
                    WHERE condition)
	  ORDER BY column_names;
	  ```
      (예제)
      (1)  범죄 검거 혹은 발생 건수가 2000건 보다 큰 경찰서 조회
      ```
	  SELECT name FROM police_station p
      WHERE EXISTS (SELECT police_station FROM crime_status c
                    WHERE p.name = c.reference AND case_number > 2000);
	  ```
      - ANY : 서브쿼리 결과 중에 최소한 하나라도 만족하면 반환
      ```
	  SELECT column_names,... 
      FROM table_name
      WHERE column_name = ANY (SELECT column_name 
                               FROM table_name 
                               WHERE condition)
      ORDER BY column_names;
	  ```
      (예제)
      (1) SNL에 출연한 적이 있는 연예인 이름 조회
      ```
      SELECT name 
      FROM celeb
	  WHERE name = ANY (SELECT host 
                        FROM snl_show);
	  ```
      - ALL : 서브쿼리 결과를 모두 만족하면 반환 (비교연산자 사용)
      ```
	  SELECT column_names,... 
      FROM table_name
	  WHERE column_name = ALL (SELECT column_name 
                               FROM table_name 
                               WHERE condition)
	  ORDER BY column_names;
	  ```
      (예제)
      (1) SNL에 출연한 적이 있는 연예인 이름 조회
      ```
	  SELECT name 
      FROM celeb
	  WHERE name = ALL (SELECT host 
						FROM snl_show 
                        WHERE id=1);
	  ```
((3)) Multiple Column
- 하나 이상의 열을 검색하는 서브쿼리
- 서브쿼리 내에 메인 쿼리 컬럼을 가져와 같이 사용되는 경우
```
SELECT column_names, ...
FROM table1_name a
WHERE (a.column1, a.column2, ...)
		IN (SELECT b.column1, b.column2, ...
        FROM table2_name b
        WHERE a.column_name = b.column_name)
ORDER BY column_names;
```
(예제)
(1) 강동원과 성별, 소속사가 같은 연예인의 이름, 성별, 소속사를 조회
```
SELECT name, sex, agency 
FROM celeb
WHERE (sex, agency) IN (SELECT sex, agency 
           				FROM celeb
                        WHERE name = "강동원");
```
profile
Data Science 스터디로그

0개의 댓글