mysql에서 JOIN 연산은 총 4~5편 정도에 걸쳐서 쓸 예정입니다. 사실, 웹 사이트에서 많이 쓸 법한 쿼리라서 그렇다고는 말을 못 하겠어요. 이전에, 카티션 곱에 대해서 이야기를 한 적이 있을 거에요.

 

 

[관련글]

[코딩/Sql] - mysql from : 어느 릴레이션에서 정보를 찾아올까?

 

 

 쭉 읽어보시면, 중간에 _order.id와 _user.id가 같은 것을 출력하라는 조건문이 들어 왔다는 것을 볼 수 있는데, 이를 자연 조인이라고 이야기 합니다. 그런데, 아래와 같은 상황을 생각해 봅시다.

 

 

 쇼핑몰 사이트를 구축할 때 꽤 자주 보이는 문제 중에 하나가 될 수도 있을 듯 싶은데요. 어떻게 해야 할까요?

 

 


 문제 길이가 짧지만, 상황을 간단하게 요약해 봅시다.

 

 user table에 있는 레코드들의 집합을 A, order table에 있는 레코드들의 집합을 B라 합시다. 고객별로 뭔가를 얻어와야 한다는 것은, 일단 user table에 접근을 해야 한다는 소리입니다. 거기에 고객 ID에 대한 정보가 있기 때문입니다. 그런데 고객에 대해서 무엇을 얻어와야 하나요? 몇 개의 주문을 했는지. 그러면 주문은 order에 있지 않을까요? 이 두 테이블에서 정보를 얻어와야 하는 건 맞아 보입니다.

 

 

 먼저, user 테이블입니다.

 

 

 다음에, 이것은 _order 테이블인데요. 보시면 3번 유저가 주문을 한 번도 하지 않았음을 알 수 있어요.

 

 

 그러면, 이 쿼리의 실행 결과는 어떻게 나올까요? customer와 _order를 카티션 곱한 것이 나올 겁니다.

 

 그러면 총 12개 행의 결과가 나올 겁니다. 만약에 where 절에 customer.id = _order.id 조건을 걸면 어떻게 될까요? 위 레코드에서 1번째 열과 3번째 열이 같은 것들만 리턴될 겁니다. 1번 chogahui가 1, 2, 3번 주문을 했고, 2번 cho가 4번 주문을 했다는, 총 4개의 결과가 리턴될 거에요.

 

 

 이 쿼리를 실행해 봅시다.

 

 id가 3인 정보는 리턴되지 않았습니다. 이것은 id가 3인 레코드는, customer 테이블에 있지만, _order에 없기 때문입니다.

 

 벤 다이어 그램으로 그려보면, customer id가 1, 2인 것은 _order에도 등장합니다. 따라서, 카티션 곱을 했을 때 결과 튜플이 <customer.id, A, _order.id, B> 이렇게 나온다고 했을 때, customer.id와 _order.id가 같은 경우에만 결과값에 출력되기 때문에, 고객 번호가 3인 정보는 당연하게도 결과 값에 포함되지 않습니다.

 

 


 우리는 벤 다이어그램에서 보라색 부분도 결과값에 포함을 시켜야 함을 알 수 있습니다. 어떻게 해야 할까요? 오른쪽 table인, _order에 나오지 않더라도, 더 정확히 말하면 왼쪽에 등장하는 고객 table의 id가 t일 때, _order를 한 고객의 id가 t인 레코드가 없더라도,  고객 table에 t가 있었다는 것을 보존해야 합니다. 연산 왼쪽에 등장하는 릴레이션을 보존하는 join을, left join이라고 합니다.

 

 문제 상황은 무엇이였나요? 고객들이 주문을 몇 개 했는지를 출력해야 한다고 했어요. 조인 조건을, customer의 id와 order를 한 고객 id가 같을 때로 걸어버렸다면요. 그런데 3번 고객 또한 result에 나와야 합니다. 뭘 보존해야 하나요? customer를 보존해야 해요. 따라서, customer는 연산의 왼쪽에, _order는 우측에 나와야 합니다.

 

 

 따라서 이렇게 쓸 수 있어요. id 값을 가지고 join 하는 건 똑같습니다.

 

 

 결과 값이 그냥 자연 조인을 했을 때와, 다른 점을 눈치 채셨나요? customer.id가 3인 데이터 또한 있다는 겁니다. 대신에, 고객 번호가 3인 레코드는 우측 table인 _order에는 없어요. 좌측에 나타난 릴레이션을 보존한 거에요. 이제 이 테이블을 가지고 정보를 뽑아봅시다. 무엇을 기준으로 돌릴 거냐면, customer.id를 가지고 group by를 돌리면 될 거에요. 그리고 그룹별로 집계를 하면 되는 것이니 count를 하면 되는데. 무엇을 집계해야 하나요? order의 수를. count(xx)는 xx가 NULL값이 아닌 것만 집계합니다.

 

 

 그러면 이렇게 쓰면 문제에서 요구하는 기능을 수행할 수 있습니다.

 

 

 최종 결과는 위와 같습니다. 즉, 왼쪽 테이블에 등장하는 레코드들은, 보존 됩니다. 설령 left table의 특정 레코드와, right table을 카티션 곱 했을 때,  ON 조건에 걸리는 게 아무것도 없다고 할지라도. 제가 도입부에서 제시한 문제 상황이 딱 맞습니다. 고객은 있지만, order가 없을 때. 고객 번호를 ON 조건에 걸면 되고, left는 고객, right는 주문 table을 넣으면 되기 때문입니다.