"Every table in the database needs to have a single theme. - 모든 테이블은 하나의 주제만 가져야 한다."
관계형 데이터베이스를 만든 분이 위와 같은 말을 했다고 하는데, 관계형 데이터 테이블이 가져야할 최소한의 규칙이 아닌가 싶네요.
관계형 데이터 테이블의 경우 주제별로 테이블을 나누어 놓으면, 추후 수정사항이 생겼을 때 해당 테이블에서만 데이터를 수정하면 다른 모든 데이터에 반영되어 편리합니다.
반면 기존의 테이블의 경우에는 데이터가 한 테이블에 있어 읽기는 좋지만, 위와 같은 수정사항이 생겼을 때는 작업을 하기 어렵다는 단점이 있습니다.
이러한 trade-off 적인 요소를 보완하기 위해 나온 기능이 데이터베이스의 JOIN 기능입니다. 관리는 관계형 데이터 모델로 하고, 필요할 경우 필요한 요소들을 모아 보기 쉬운 테이블을 생성해주는 기능이죠.
생활코딩에서 예시로 보여준 테이블을 활용해 JOIN 사용법을 알아보겠습니다. MySQL을 사용해 테이블을 조작할 예정이므로, 아직 MySQL에 익숙하지 않으신 분은 아래 글을 참조해보세요!
LEFT JOIN은 기준으로 둔 테이블을 왼쪽에 두고, 이 테이블의 데이터를 기준으로 다음 테이블의 데이터를 정렬하는 방식 입니다.
왼쪽 테이블의 값은 모두 노출되야하기 때문에, 만약에 오른쪽 테이블에 왼쪽 테이블과 맞는 값이 없다면 NULL
로 데이터가 채워집니다.
먼저 topic
과 author
테이블을 LEFT JOIN
해보겠습니다.
# 명령어 구성
$ SELECT * FROM TableA LEFT JOIN TableB ON A.key = B.key
# 실제 명령어 작성
$ mysql> select * from topic left join author on topic.author_id = author.aid;
+-----+------------+------------------+-----------+------+---------+-------+------------+
| tid | title | description | author_id | aid | name | city | profile_id |
+-----+------------+------------------+-----------+------+---------+-------+------------+
| 1 | HTML | HTML is ... | 1 | 1 | egoing | seoul | 1 |
| 2 | CSS | CSS is ... | 2 | 2 | leezche | jeju | 2 |
| 3 | JavaScript | JavaScript is .. | 1 | 1 | egoing | seoul | 1 |
| 4 | Database | Database is ... | NULL | NULL | NULL | NULL | NULL |
+-----+------------+------------------+-----------+------+---------+-------+------------+
4 rows in set (0.00 sec)
출력된 결과물을 보면, topic
을 구성하는 모든 행을 기준으로 데이터가 출력되었고, author
의 데이터 중 [topic
의 author_id
]와 연결되는 값이 없는 [aid=3
] 값은 출력되지 않았습니다. 그리고 [topic
의 tid=4
]와 연결되는 author
의 데이터가 존재하지 않아, 해당 행의 author
데이터는 모두 NULL
로 처리되었습니다.
이번에는 LEFT JOIN
으로 테이블 하나를 더 합쳐보겠습니다.
$ mysql> select * from topic left join author on topic.author_id = author.aid left join profile on author.profile_id = profile.pid;
+-----+------------+------------------+-----------+------+---------+-------+------------+------+-----------+------------------+
| tid | title | description | author_id | aid | name | city | profile_id | pid | title | description |
+-----+------------+------------------+-----------+------+---------+-------+------------+------+-----------+------------------+
| 1 | HTML | HTML is ... | 1 | 1 | egoing | seoul | 1 | 1 | developer | developer is ... |
| 2 | CSS | CSS is ... | 2 | 2 | leezche | jeju | 2 | 2 | designer | designer is .. |
| 3 | JavaScript | JavaScript is .. | 1 | 1 | egoing | seoul | 1 | 1 | developer | developer is ... |
| 4 | Database | Database is ... | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL |
+-----+------------+------------------+-----------+------+---------+-------+------------+------+-----------+------------------+
4 rows in set (0.00 sec)
동일한 규칙으로 두번째 테이블의 값과 세번째 테이블의 값을 매칭시켜서 값을 가져왔습니다. 근데 각각의 테이블의 인덱스와 같은 이름의 필드값들이 한데 모이니 좀 지저분해 보입니다. 여기서 우리는 원하는 필드를 출력하고, 또 필드명을 다른 이름으로 바꿈으로써 테이블을 보기 좋게 수정할 수 있습니다.
먼저 원하는 값을 뽑아봅시다. 저는 [tid, title, name, city, title]
정보를 뽑아보고 싶습니다. 이러기 위해서는 select
다음에 오는 [*]
값을 바꿔주면 됩니다.
이제 명령어를 바꿔쳐보면, $ mysql> select tid, title, name, city, title...?
치다보니 앞에서 쳤던 [title]
이 또 나옵니다. 이렇게 같은 값이 여러번 나오면 SQL은 어떤 값을 달라는건지 알지 못해서 에러가 뜹니다.
ERROR 1052 (23000): Column 'title' in field list is ambiguous
이때는 겹치는 값을 특정 테이블의 값이라고 특정해주면 됩니다.
topic
에 있는 title
은 [topic.title]
로 바꾸고, profile
의 title
은 job_title
으로 바꿔서 출력하기 위해 [profile.title as job_title]
로 바꿔줍니다.
그러면 짠 하고 원하는 테이블이 나타납니다.
$ mysql> select tid, topic.title, name, city, profile.title as job_title from topic left join author on topic.author_id = author.aid left join profile on author.profile_id = profile.pid;
+-----+------------+---------+-------+-----------+
| tid | title | name | city | job_title |
+-----+------------+---------+-------+-----------+
| 1 | HTML | egoing | seoul | developer |
| 2 | CSS | leezche | jeju | designer |
| 3 | JavaScript | egoing | seoul | developer |
| 4 | Database | NULL | NULL | NULL |
+-----+------------+---------+-------+-----------+
4 rows in set (0.00 sec)
INNER JOIN
은 불러오는 테이블의 교집합이라고 보면 됩니다. 각 테이블에 동시에 존재하는 값들만 새로운 테이블로 출력됩니다. 그렇기 때문에 INNER JOIN
에는 테이블간 비매칭으로 인한 NULL 값은 존재하지 않습니다. 꽤나 기준이 엄격한 모델이라고 할 수 있죠.
먼저 topic
과 author
테이블을 INNER JOIN
해보겠습니다. LEFT JOIN
때와 다르게 topic
의 tid=4
값이 사라졌습니다. topic
에만 데이터가 있어서 출력되지 않은거죠.
# 명령어 구성
$ SELECT * FROM TableA INNER JOIN TableB ON A.key = B.key
# 실제 명령어 작성
$ mysql> select * from topic inner join author on topic.author_id = author.aid;
+-----+------------+------------------+-----------+-----+---------+-------+------------+
| tid | title | description | author_id | aid | name | city | profile_id |
+-----+------------+------------------+-----------+-----+---------+-------+------------+
| 1 | HTML | HTML is ... | 1 | 1 | egoing | seoul | 1 |
| 2 | CSS | CSS is ... | 2 | 2 | leezche | jeju | 2 |
| 3 | JavaScript | JavaScript is .. | 1 | 1 | egoing | seoul | 1 |
+-----+------------+------------------+-----------+-----+---------+-------+------------+
3 rows in set (0.00 sec)
이번에는 테이블 하나를 더 추가해서 출력해보겠습니다.
# mysql> select tid, topic.title, name,city,profile.title as job_title from topic inner join author on topic.author_id = author.aid inner join profile on author.profile_id = profile.pid;
+-----+------------+---------+-------+-----------+
| tid | title | name | city | job_title |
+-----+------------+---------+-------+-----------+
| 1 | HTML | egoing | seoul | developer |
| 2 | CSS | leezche | jeju | designer |
| 3 | JavaScript | egoing | seoul | developer |
+-----+------------+---------+-------+-----------+
3 rows in set (0.00 sec)
여기서도 LEFT JOIN
때와 다르게 NULL
값이 포함된 열은 출력되지 않은 것을 알 수 있습니다.
이외 JOIN
에는 RIGHT, FULL OUTER, EXCLUSIVE
가 있는데, 사용빈도가 높지 않아 간단히 설명하고 끝마치려 합니다.