어떻게 흩어진 표를 잇기, 조인
주문 표에는 누가 무엇을 샀는지가 적혀 있지만, '누가'는 고객번호로만 남아 있다. 그 번호의 주인이 누구인지, 이름은 고객 표에 따로 있다. 그렇다면 이 주문을 한 사람의 이름은 어떻게 알아낼까? 두 표에 똑같이 들어 있는 고객번호를 실마리로 삼아 번호가 같은 줄끼리 짝을 지으면 된다. 흩어진 표를 함께 가진 열로 이어 붙이는 일, 이것을 조인이라고 해요.
정보가 두 표에 나뉘어 있어요
앞 레슨에서는 표 하나에 SQL로 물어 원하는 줄을 골라냈다. 그런데 실제 데이터베이스에서 필요한 정보가 한 표에 다 모여 있는 경우는 드물다. 가게라면 주문은 주문 표에 적고, 손님의 이름과 연락처는 고객 표에 따로 적어 둔다.
일부러 그렇게 나눈 것이에요. 주문이 들어올 때마다 손님 이름과 연락처를 줄마다 다시 적으면 같은 내용이 여러 번 쌓이고, 연락처가 바뀌면 그 줄을 모두 찾아 고쳐야 하기 때문이다. 먼저 두 표를 나란히 펼쳐 보자.
표 머리를 눌러 하나씩 펼쳐 보자. 주문 표와 고객 표가 서로 다른 열을 따로 들고 있는 것이 보여요.
두 표를 펼치니 맡은 일이 다르다. 주문 표에는 주문 번호, 고객번호, 물건이 있고, 고객 표에는 고객번호와 이름이 있다. 주문 표만 봐서는 연필을 산 사람에 대해 번호밖에 알 수 없어요.
'연필을 산 사람의 이름은?' 같은 물음은 두 표를 넘나든다. 물건은 이쪽 표에, 이름은 저쪽 표에 있으니 둘을 이어야 답이 나와요. 이을 실마리가 어디에 있는지부터 찾아보자.
두 표가 함께 가진 열을 찾는다
두 표의 열 이름을 나란히 놓고 보면 양쪽에 다 있는 것이 하나 있다. 고객번호다. 고객 표에서 고객번호는 손님마다 하나씩 붙은, 남과 겹치지 않는 번호라서 이 번호만 알면 어느 손님인지 딱 정해진다.
주문 표의 고객번호는 그 번호를 그대로 옮겨 적은 것이다. 그래서 고객 표의 고객번호를 기본 키, 그것을 가리키는 주문 표의 고객번호를 외래 키라고 불러요. 두 표가 함께 가진 이 열이 둘을 잇는 다리가 된다.
열 이름을 하나씩 눌러 보자. 두 표에 모두 있는 열을 고르면 불이 들어오고, 한쪽 표에만 있는 열을 고르면 어느 표에만 있는지 알려 줘요.
물건은 주문 표에만, 이름은 고객 표에만 있었다. 두 표에 모두 있는 열은 고객번호 하나뿐이다.
이 열의 값이 같으면 두 줄은 같은 손님을 가리킨다. 주문 표에 적힌 고객번호 7과 고객 표의 고객번호 7은 같은 사람, 하준이에요. 그러니 이 열을 길잡이로 삼아 줄끼리 짝을 지으면 된다.
같은 번호끼리 짝을 짓는다
짝을 짓는 방법은 단순하다. 주문 표에서 줄 하나를 골라 그 줄의 고객번호를 읽고, 고객 표에서 같은 고객번호를 가진 줄을 찾는다. 번호가 같으면 두 줄은 짝이에요.
한 손님이 여러 번 주문할 수도 있다. 그러면 주문 표의 여러 줄이 고객 표의 한 줄을 함께 가리킨다. 아래에서 연필 주문과 지우개 주문을 차례로 눌러 보면 둘 다 같은 손님에게 이어진다. 손님 한 명에 주문이 여럿 달리는 이런 관계를 일대다라고 해요.
주문 표의 줄을 눌러 보자. 같은 고객번호를 가진 고객 표의 줄에 불이 들어오고, 그 주문이 누구의 것인지 아래에 나와요.
번호만 적혀 있던 주문 옆에 이제 사람 이름이 따라온다. 연필 주문과 지우개 주문은 둘 다 하준에게, 공책 주문은 민서에게 이어졌다.
데이터베이스는 이 일을 줄마다 되풀이한다. 기본 키에는 대개 인덱스가 저절로 붙어 있어서, 표가 커도 고객 표에서 짝을 빨리 찾아낸다. 이렇게 찾은 짝을 한 줄로 붙이면 어떤 표가 나올까?
짝지은 줄을 한 표로 붙여요
짝지은 두 줄을 옆으로 붙이면 칸이 늘어난 새 줄이 된다. 주문의 칸 옆에 그 손님의 칸이 나란히 서고, 두 표에 다 있던 고객번호는 한 번만 둔다. 이렇게 만든 줄을 모으면 무엇을 샀는지와 누가 샀는지가 한 줄에 같이 담긴 결과 표가 나와요.
SQL에서는 두 표 이름 사이에 JOIN을 쓰고, 어느 열끼리 값이 같아야 하는지는 ON으로 적는다. 앞 레슨의 SELECT와 WHERE도 그대로 함께 쓸 수 있다.
합치기 단추를 눌러 보자. 두 표가 고객번호를 기준으로 한 줄씩 이어지며, 무엇을 누가 샀는지가 한 표에 모여요. 다시 누르면 처음처럼 나뉜다.
결과 표에는 하준이라는 이름이 두 번 나온다. 그래도 고객 표에 하준은 여전히 한 줄로만 저장돼 있다. 이름이 겹치는 곳은 물음에 답하려고 잠깐 만든 결과 표뿐이고, 저장된 표는 그대로다.
짝이 없는 줄은 결과에서 빠진다는 점도 기억해 두자. 아직 한 번도 주문하지 않은 손님이 고객 표에 있다면 짝지을 주문이 없으니, 기본 조인의 결과에는 나오지 않아요. 짝 없는 줄까지 남기고 싶을 때 쓰는 조인은 따로 있다.
정리
정리하면 이렇다. 데이터베이스는 같은 정보를 여러 번 적지 않으려고 정보를 여러 표에 나누어 담는다. 표를 넘나드는 물음에 답하려면 두 표가 함께 가진 열을 찾고, 그 열의 값이 같은 줄끼리 짝을 지어 옆으로 붙인다.
그러면 한 표처럼 읽을 수 있는 결과 표가 나와요. 나누어 저장하고 물을 때 잇는 것, 이것이 조인이다.
핵심을 차례로 눌러 되짚어 보자. (표가 두 개 → 공통 열 찾기 → 공통 열로 짝 맞추기 → 한 표로 합치기)
이제 흩어진 표를 함께 가진 열로 이어 물을 수 있다. 표를 나누어 두어도 답을 얻는 데는 문제가 없다는 뜻이에요.
그렇다면 표는 어떤 기준으로 나눠야 할까? 손님 이름을 주문마다 적으면 무엇이 곤란해지는지, 겹치는 정보를 어떻게 덜어 내는지를 다음 레슨 정규화에서 다룬다.