#3 프로그래밍 개발자 교육 - SQL : 테이블 join의 유형
이번 시간에는 SQL로 데이터를 조회할 때, 두 테이블간의 join 하는 유형에 대해 교육을 해 보겠습니다. 테이블별로 존재 데이터를 서로의 공통점을 이용하여 나란히 데이터를 출력하게 하기위헤서 join을 사용합니다. 왜만한 데이터 추출용 SQL에는 거의 대부분이 join을 이용해야 하기 때문에 반드시 알아두어야 합니다. Join을 할 대상 테이블에 데이터가 어떤 식으로 존재하는 지 사전에 숙지를 해야 합니다. 잘못된 join은 문법오류가 나면 차라리 다행이지만 문법이 맞기 때문에 수행이 되어 버리면 DB 성능이 굉장히 저하되는 물리적 현상과 더불어 잘못된 데이터가 산출되기 때문에 데이터 신뢰성에 문제가 발생하게 됩니다.
먼저 join 할 대상이 되는 테이블에 대해 알아보기로 합시다. 우선 DB 서비스를 기동시킵니다. 이전에는 windows service 관리자를 실행시켜서 시동했는데, Task바 오른쪽 시계나오는 부분에 나오는 Tray 영역을 통해서도 서비스를 기동시킬 수 있습니다. 메뉴 전체를 캡쳐가 안되서 아이콘만 캡쳐했는데 빨간색 돌고래 아이콘에 잘보면 동그라밍 아래 빨간색 상자 즉, 정지 모습이 보입니다 .이 아이콘을 오른 쪽 클릭하면 MySQL80 Stopped 오른쪽 확장메뉴를 누르면 Start 메뉴가 보이는데 그걸 클릭하면 빨간색이던 아이콘이 흰색으로 보이고 작은 동그라미 안에도 초록색 삼각형으로 바뀝니다. 글로는 뭐 복잡한데 아래 이미지를 보고 한번 해보시면 어려운 것이 전혀 아닙니다.
MySQL Workbench 를 실행합니다. 저는 Windows 8을 사용하고 있기 때문에 아래와 같이 검색해서 찾아 실행합니다.
아래 Local instance MySQL80 을 클릭합니다.
Join은 4가지를 사용합니다. 이외에도 더 있지만 현실적으로 이 4가지외에는 사용한 적이 없습니다. 4가지는 inner join, left outer join, right outer join, full outer join 입니다. 대소문자는 신경 안쓰셔도 됩니다. 사실 inner join 이냐 아니냐로 구별합니다. 첫번째, inner join 입니다. Inner join은 join 하는 테이블 간에 연켤 컬럼에 동일한 데이터가 존재하는 경우만 데이터가 추출 됩니다. Inner join은 Inner를 빼고 join만 써도 됩니다. SQL을 작성하다보면 줄맞추기가 중요합니다. 줄을 잘 맞춰야 해석하기가 용이하거든요. 이 줄 맞추기 때문에 저는 inner를 잘 안쓰는 편입니다.
두번째 Left outer join 은 위의 예제로 보면 city 에 데이터가 없더라도 빈값으로 데이터를 출력할 때 필요합니다. 아래 SQL을 보면 country 와 city를 join하는데, city는 KOR 을 제외하고 join 합니다. 그리고 최종조건에는 country테이블의 Code가 KOR 인 것만 추출합니다. 이렇게 inner join을 하는 경우에는 데이터가 추출이 되지 않습니다. Inner join할 때는 2개 테이블간에 on 구문으로 join 한 컬럼에 동일한 값이 존재 해야만 조회조건이 달성됩니다.
이 join을 left outer join으로 바꿔보면 아래와 같이 결과가 나옵니다. Join하는 테이블인 city 의 왼쪽에 기술된 테이블인 country 기준으로 비록 city 에 해당되는 값이 없더라도 NULL 값으로 출력이 됩니다. DB 조회 툴마다 차이는 있는데 어떤 툴은 NULL 표시 자체없이 빈공간으로 나오기도 합니다. NULL 이란 아무 값도 없다는 뜻입니다. 결과에서 왼쪽 Code, Name 컬럼은 country 테이블에서 읽은 것이라 데이터가 있지만, city 테이블에서 읽는 Name과 Population은 애초에 join할 때 KOR을 제외하고 읽은 거라 출력할 수 있는 게 없습니다.
세번째 right outer join은 left outer join과 순서가 반대입니다. 아래 예제는 좀 어렵게 느껴지실 수도 있습니다. 자, Right outer join 이기 때문에 데이터 출력은 오른쪽에 기술된 city 테이블 기준으로 확장해서 출력됩니다. Join 조건에 country 테이블의 code <> 'KOR' 조건으로 한국은 빼고 country 테이블 데이터를 읽을 겁니다. Where 조건에서 city 테이블에서 city.Countrycode = 'KOR' and city.Name = 'Seoul' 인 조건으로 서울데이터만 읽어오게 읽어옵니다. 결과적으로 country 테이블에서 일거오는 Code와 Name은 NULL 값 즉, 빈 값으로 출력되고 city 테이블 값만 출력됩니다.
예제 SQL이 좀 꼬아놓은 거라 이해가 잘 안가실 수도 있습니다. 저도 SQL을 작성할 때 왼쪽에서 오른쪽으로 습관으로 인해 right outer join은 잘 안씁니다. 그리고 한 SQL 내에서 left otuer join과 right outer join을 섞어 쓰지 않습니다. SQL을 머리속으로 해석하며 데이터 처리과정을 상상할 때 상당히 어려워지고 결국 실수로 이어질 겁니다. 그래서 실제론 inner join과 left outer join 만으로도 충분히 문제를 해결할 수 있습니다.
4번째로 full outer join 이 있습니다. 이건 join 한 두 테이블간에 서로 없는 컬럼까지 포함해서 출력하는 것입니다. 안타깝게도 MySQL 에서는 full outer join 문법을 지원하지 않습니다. 아래 그림으로 우선 개념만 이해하시길 바랍니다.
예를 들어 아래와 같이 타짜 1편과 2편 출연진 테이블이 있다고 봅시다.
< 예상 결과 >
왼쪽은 타짜1편 출연진이고 오른쪽은 2편 출연진입니다. 타짜와 타짜2 모두 출연한 배우는 나란히 옆에 출력되지만, 어느 한 쪽만 출연한 배우는 옆에 NULL (빈 값)이 출력됩니다. 위에서 봤던 left outer join과 right outer join 이 모두 반영된 결과 입니다.
마지막으로 self join과 cross join 이란 것도 있습니다. 제 생각에는 엄밀히 말하자면 self join 이란 것은 위에서 분류하는 join의 분류 기준과는 다릅니다. 동일한 테이블을 별명(alias)만 다르게 해서 join하는 것이지만 실제 문법은 inner join 이나 left outer join등을 씁니다. 이 부분은 다음 교육 과정에서 설명할 테니 너무 신경쓰시지 않으셔도 됩니다. cross join은 의도적으로 cartesian 을 일으키는 것인데 결국 경우의 수를 모두 만드는 것입니다. Join할 때 on 절에서 join 컬럼을 지정하는데 cross join 에서는 on 절을 안씁니다. 그럼 중학 수학에서 배웠던 행렬의 곱처럼 경우의 수를 모두 구하는 것과 비슷합니다. Cross join을 지금 시점에서 의도적으로 배울 필요는 없다고 생각합니다. SQL을 작성하다보면 실수로 의도치 않게 cross join을 일으키게 됩니다. 따라서 join 은 위에서 말한 inner join과 left outer join, right outer join, full outer join 만 보시고 나머지는 이번 글을 읽고 넘어가시길 권고드립니다.
이번 시간도 수고하셨습니다. MySQL80을 시작했을 때와 반대로 Stop 하시길 바랍니다.