
여러 개의 SQL문을 합쳐서 하나의 SQL문으로 만들어 주는 명령어이다.
주의! SQL문을 적용하는 컬럼의 개수가 같아야 한다. 같지 않으면 오류가 발생한다.
UNION : 중복된 값을 제거하고 검색 결과를 보여준다.
UNION ALL : 중복된 값을 포함해 모두 보여준다.
SELECT column1, column2, ... FROM table_A;
UNION | UNION ALL
SELECT column1, column2, ... FROM table_B;


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

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

▶ 컬럼 개수가 맞지 않아 오류가 발생한다.
컬럼 개수를 맞춰 주고 다시 실행해 보면 결과값은 나오지만,
컬럼의 종류가 달라 컬럼 값에 맞지 않는 데이터가 같이 결과에 출력된다.
두 개 이상의 테이블을 특정 컬럼을 기준으로 결합하는 명령어이다.


ON : 조인의 기준을 정해준다. 해당 컬럼의 값이 같을 때 조인한다. SELECT tableA.column1, tableA.column2, ..., tableB.column1, tableB.column2, ...
FROM tableA
INNER JOIN tableB
ON tableA.column_name = tableB.column_name WHERE condition;

SELECT tableA.column1, tableA.column2, ..., tableB.column1, tableB.column2, ...
FROM tableA --> left table에 해당
LEFT JOIN tableB --> right table에 해당
ON tableA.column_name = tableB.column_name WHERE condition;

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

SELECT tableA.column1, tableA.column2, ..., tableB.column1, tableB.column2, ...
FROM tableA FULL OUTER JOIN tableB
ON tableA.column_name = tableB.column_name WHERE condition;
FULL OUTER JOIN = (LEFT JOIN) UNION (RIGHT JOIN)
SELECT tableA.column1, tableA.column2, ..., tableB.column1, tableB.column2, ...
FROM tableA
LEFT JOIN tableB
ON tableA.column_name = tableB.column_name WHERE condition
UNION --> 중복되는 부분은 삭제하고 결합해 준다.
SELECT tableA.column1, tableA.column2, ..., tableB.column1, tableB.column2, ...
FROM tableA
RIGHT JOIN tableB
ON tableA.column_name = tableB.column_name WHERE condition;

SELECT tableA.column1, tableA.column2, ..., tableB.column1, tableB.column2, ...
FROM tableA, tableB, ...
WHERE condition; --> WHERE 절에 결합의 기준을 명시한다.

하나의 SQL 문 안에 포함되어 있는 또 다른 SQL 문을 말한다.
메인쿼리가 서브쿼리를 포함하는 종속적인 관계이다.
⭕ 서브쿼리는 메인쿼리의 컬럼 사용이 가능하다.
❌ 메인쿼리는 서브쿼리의 컬럼 사용이 불가능하다.
Subquery 사용시 주의사항
💦 서브쿼리는 괄호로 묶어서 사용한다.
💦 단일 행 혹은 복수 행 비교 연산자와 함께 사용 가능하다.
💦 서브쿼리에서는 ORDER BY를 사용할 수 없다.
스카라 서브쿼리는 SELECT 절에서 사용하는 서브쿼리이다.
스카라 서브쿼리의 결과는 하나의 Column이어야 한다.
SELECT column1, (SELECT column2 FROM table2_name WHERE condition)
FROM table1_name WHERE condition;
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='검거';
-- ⬇ 실행결과 ⬇ --
+--------------------+--------------------+
| 은평강도검거건수 | 서울강도검거평균 |
+--------------------+--------------------+
| 1 | 4.1935 |
+--------------------+--------------------+
인라인 뷰는 FROM 절에서 사용하는 서브쿼리이다.
메인쿼리에서는 인라인 뷰에서 조회한 Column 만 사용 가능하다.
SELECT a.column_name, b.column_name, ...
FROM table1_name a, (SELECT column1, column2, ... FROM table2_name) b
WHERE condition;
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;
-- ⬇ 실행결과 ⬇ --
+----------------+------------+-------------+
| police_station | crime_type | case_number |
+----------------+------------+-------------+
| 중부 | 폭력 | 997 |
| 종로 | 폭력 | 964 |
| 남대문 | 절도 | 699 |
| 서대문 | 폭력 | 1292 |
| 혜화 | 폭력 | 747 |
| 용산 | 폭력 | 1617 |
| 성북 | 폭력 | 672 |
| 동대문 | 폭력 | 1784 |
=, >, >=, <, <=, <>, !=)와 사용되는 경우이다. SELECT column_names,... FROM table_name
WHERE column_name = (SELECT column_name FROM table_name WHERE condition)
ORDER BY column_names;
SELECT name FROM celeb WHERE name = SELECT host FROM snl_show;
- 괄호가 없으면 에러가 발생한다.
SELECT name FROM celeb WHERE name = (SELECT host FROM snl_show);
- 한 개 이상의 결과값을 가지는 경우 에러가 발생한다.
SELECT name FROM celeb WHERE name = (SELECT host FROM snl_show WHERE id=1);
-- ⬇ 실행결과 ⬇ --
+-----------+
| name |
+-----------+
| 강동원 |
+-----------+
- 서브쿼리의 검색 결과는 한 개의 결과값이어야 한다.
IN : 서브쿼리 결과 중에 포함될 때 SELECT column_names,... FROM table_name
WHERE column_name IN (SELECT column_name FROM table_name WHERE condition)
ORDER BY column_names;
SELECT host FROM snl_show
WHERE host IN (SELECT name FROM celeb WHERE job_title LIKE '%영화배우%');
-- ⬇ 실행결과 ⬇ --
+-----------+
| host |
+-----------+
| 강동원 |
| 차승원 |
+-----------+
EXISTS : 서브쿼리 결과에 값이 있으면 True를 반환 SELECT column_names,... FROM table_name
WHERE EXISTS (SELECT column_name FROM table_name WHERE condition)
ORDER BY column_names;
SELECT name FROM police_station p
WHERE EXISTS (SELECT police_station FROM crime_status c
WHERE p.name = c.reference AND case_number > 2000);
-- ⬇ 실행결과 ⬇ --
+------------------------+
| name |
+------------------------+
| 서울강남경찰서 |
| 서울강서경찰서 |
| 서울관악경찰서 |
| 서울구로경찰서 |
| 서울노원경찰서 |
| 서울송파경찰서 |
| 서울영등포경찰서 |
| 서울중랑경찰서 |
+------------------------+
ANY : 서브쿼리 결과 중에 최소한 하나라도 만족하면 True를 반환 SELECT column_names,... FROM table_name
WHERE column_name = ANY (SELECT column_name FROM table_name WHERE condition)
ORDER BY column_names;
SELECT name FROM celeb
WHERE name = ANY (SELECT host FROM snl_show);
-- ⬇ 실행결과 ⬇ --
+-----------+
| name |
+-----------+
| 강동원 |
| 유재석 |
| 차승원 |
| 이수현 |
+-----------+
ALL : 서브쿼리 결과를 모두 만족하면 True를 리턴 (비교연산자를 사용) SELECT column_names,... FROM table_name
WHERE column_name = ALL (SELECT column_name FROM table_name WHERE condition)
ORDER BY column_names;
SELECT name FROM celeb
WHERE name = ALL (SELECT host FROM snl_show WHERE id=1);
-- ⬇ 실행결과 ⬇ --
+-----------+
| name |
+-----------+
| 강동원 |
+-----------+
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;
SELECT name, sex, agency FROM celeb
WHERE (sex, agnecy) IN (SELECT sex, agency FROM celeb WHERE name='강동원');
-- ⬇ 실행결과 ⬇ --
+-----------+------+----------------------+
| name | sex | agency |
+-----------+------+----------------------+
| 강동원 | M | YG엔터테이먼트 |
| 차승원 | M | YG엔터테이먼트 |
+-----------+------+----------------------+