테이블의 집합 연산에서는 세로 방향
으로 데이터가 합쳐진다. 테이블 결합에서는 가로 방향
으로 데이터가 늘어나게 된다.
보통 데이터베이스는 많은 데이터를 여러 개의 테이블에 나눠 저장한다. 이처럼 여러 개로 나뉜 데이터를 하나로 묶어내는 방법이 테이블 결합
이다. 결합을 이해하는 동시에 기본이 되는 개념이 집합론의 ‘곱집합’이다.
곱집합과 교차결합
곱집합 : 두 개의 집합을 곱하는 연산방법
집합 A는 {X,Y,Z}라는 요소를 갖고 집합 B는 {1,2,3}이라는 요소를 갖는다. 집합 A와 집합 B의 곱집합은 집합 A의 요소 X에 집합 B의 각 요소를 붙여 계산하는 것
이다.
SELECT 명령의 FROM에서 두 개의 테이블을 지정하면 이것은 곱집합으로 계산된다.
테이블 test1
A |
---|
X |
Y |
Z |
테이블 test2
B |
---|
1 |
2 |
3 |
1
SELECT * FROM test1, test2;
또는
1
SELECT * FROM test1 CROSS JOIN test2
결과
A | B |
---|---|
X | 1 |
Y | 1 |
Z | 1 |
X | 2 |
Y | 2 |
Z | 2 |
X | 3 |
Y | 3 |
Z | 3 |
교차결합
은 두 개의 테이블을 곱집합으로 계산한다.
UNION
을 이용한 테이블의 결합은 세로 방향으로 데이터가 결합되는 반면에 위와 같이 테이블을 결합하면 데이터가 가로 방향으로 결합되는 것을 알 수 있다.
내부결합
두 개이상의 테이블을 결합할 땐 교차결합보다 내부결합
을 자주 사용한다.
상품테이블
상품코드 | 상품명 | 가격 |
---|---|---|
0001 | 상품A | 100 |
0002 | 상품B | 200 |
0003 | 상품C | 300 |
위 테이블에서 ‘상품코드’는 상품테이블의 PK키로 설정했다.
재고테이블
상품코드 | 재고수 |
---|---|
0001 | 200 |
0002 | 500 |
0003 | 800 |
상품코드를 통해 상품 테이블과 연결할 수 있다.
목표는 내부결합을 사용해 아래와 같은 테이블을 표시하는 것이다.
상품명 | 재고수 |
---|---|
상품A | 200 |
상품B | 500 |
상품C | 800 |
상품명은 상품테이블에서 재고수는 재고테이블에서 가져와 가로로 나열해야 한다.
FROM을 사용해 상품테이블과 재고테이블 교차결합
1
SELECT * FROM 상품, 재고;
상품코드 | 상품명 | 가격 | 상품코드 | 재고수 |
---|---|---|---|---|
0001 | 상품A | 100 | 0001 | 200 |
0002 | 상품B | 200 | 0001 | 200 |
0003 | 상품C | 300 | 0001 | 200 |
0001 | 상품A | 100 | 0002 | 500 |
0002 | 상품B | 200 | 0002 | 500 |
0003 | 상품C | 300 | 0002 | 500 |
0001 | 상품A | 100 | 0003 | 800 |
0002 | 상품B | 200 | 0003 | 800 |
0003 | 상품C | 300 | 0003 | 800 |
이렇게 만든 테이블에서 WHERE
로 상품코드가 같은 상품을찾는다.
1
2
SELECT * FROM 상품, 재고
WHERE 상품.상품코드 = 재고.상품코드;
상품코드 | 상품명 | 가격 | 상품코드 | 재고수 |
---|---|---|---|---|
0001 | 상품A | 100 | 0001 | 200 |
0002 | 상품B | 200 | 0002 | 500 |
0003 | 상품C | 300 | 0003 | 800 |
상품명과 재고수만 반환하도록 SELECT 명령에 열을 지정한다.
1
2
SELECT 상품.상품명, 재고.재고수 FROM 상품, 재고
WHERE 상품.상품코드 = 재고.상품코드;
결과
상품명 | 재고수 |
---|---|
상품A | 200 |
상품B | 500 |
상품C | 800 |
INNER JOIN으로 내부결합
위의 FROM을 이용해 곱집합에서 WHERE로 열을 지정하는 방법은 구식이다. 같은 결과를 INNER JOIN
을 사용해 표시할 수 있다.
SELECT * FROM 테이블1 INNER JOIN 테이블2 ON 결합조건
1
2
3
SELECT 상품.상품명, 재고.재고수
FROM 상품 INNER JOIN 재고
ON 상품.상품코드 = 재고.상품코드;
- 상품 테이블과 재고 테이블 모두에 데이터가 있어야 inner join을 사용해 결과를 출력할 수 있다.
교집합
의 개념이라고 생각하면 쉽다.
예제
Customers 테이블과 Orders 테이블을 inner join을 사용해 결합해보자.
1
2
3
SELECT *
FROM Orders
INNER JOIN Customers ON Orders.CustomerId = Customers.CustomerID
왼쪽에 Orders 테이블이, 오른쪽에 Customers테이블이 붙는다.
테이블을 하나 더 join하고 싶을 때는 INNER JOIN
을 한번 더 사용한다.
1
2
3
4
SELECT *
FROM Orders
INNER JOIN Customers ON Orders.CustomerId = Customers.CustomerID
INNER JOIN Shippers ON Orders.ShipperID = Shippers.ShipperID
왼쪽에 Orders테이블이, 가운데에 Customers테이블이, 오른쪽에 Shippers 테이블이 붙는다.
이 이상으로도 INNER JOIN을 사용해 테이블을 더 붙일 수 있다.
외부결합
외부결합은 어느 한 쪽에만 존재하는 데이터행을 어떻게 다룰지
를 변경할 수 있는 방법이다. INNER JOIN을 제외한 모든 join은 외부결합이라고 생각하면 된다.
보통은 join할 때 left join을 통일해 사용해야 테이블 관계 혹은 구조를 알아보기 쉽기때문에 right join보다 left join을 더 자주 사용한다.
상품 테이블에 상품코드가 0009인 행을 새롭게 추가한다.
상품테이블
상품코드 | 상품명 | 가격 |
---|---|---|
0001 | 상품A | 100 |
0002 | 상품B | 200 |
0003 | 상품C | 300 |
0009 | 상품D | 400 |
재고 테이블에는 아직 이 새로운 상품에 대한 데이터가 없다. 이 상태에서 곱집합을 구해도 0009=0009가 되는 행은 존재하지 않으므로 내부결합 결과에선 상품코드가 0009인 상품은 제외된다. 이 경우에 외부결합
을 사용한다. 외부결합은 결합하는 테이블 중 어느 쪽을 기준으로 할 지 결정할 수 있다.
상품테이블을 기준으로 LEFT JOIN
을 사용한다.
1
2
3
SELECT 상품.상품명, 재고.재고수
FROM 상품 LEFT JOIN 재고
ON 상품.상품코드 = 재고.상품코드;
결과
상품명 | 재고수 |
---|---|
상품A | 200 |
상품B | 500 |
상품C | 800 |
상품D | NULL |
재고 테이블엔 0009에 대한 데이터가 없어 값이 NULL
로 표시된다.
LEFT JOIN 예제
Users 테이블과 Orders 테이블을 결합하는데 한번도 주문한 적 없는 User도 출력하고 싶다.
1
2
3
SELECT *
FROM Users
LEFT JOIN Orders ON Users.ID = Orders.userID
Inner join을 사용하면 주문을 한번도 한 적 없는 (Orders테이블에 데이터가 없는) User의 데이터는 출력되지 않는다.
한번도 주문한 적 없는 User의 데이터만 보고 싶을 땐 where
절을 추가해서 표현할 수 있다.
1
2
3
4
SELECT *
FROM Users
LEFT JOIN Orders ON Users.ID = Orders.userID
WHERE orderID IS NULL