brunch

You can make anything
by writing

C.S.Lewis

by 김유환 Oct 16. 2019

17. 중간 결과 테이블

SELECT를 통해 선택한 테이블을 다시 한번 SELECT 하기

배경

지난 글 GROUP BY 에서 우리가 SELECT 문을 요청하면 DBMS 가 어떻게 데이터를 선택, 가공, 정렬해서 결과값을 보여주는지 살펴보았습니다. 이 과정을 다시 한번 떠올려보시면, 데이터베이스는 결국 테이블로 시작해서 테이블로 끝난다는 것을 알 수 있습니다.


다시 한번 복기해봅시다. 데이터는 데이터베이스안에 테이블 형태로 저장되어있습니다. SELECT 와 WHERE 을 이용해서 원하는 열 혹은 행을 선택한 데이터 역시 하나의 테이블 형태로 볼 수 있습니다. 선택된 데이터를 가공하는 과정에서 GROUP BY를 이용하면, 그룹으로 묶여진 열의 값에 따라 여러개의 테이블로 나누어지게 됩니다. 나누어진 테이블에 함수를 적용해 다시 합친 결과 역시 다시 테이블의 형태를 가지게 됩니다. 가공이 마쳐진 테이블을 ORDER BY 를 이용해 원하는 순서로 정렬하고, LIMIT 을 이용해 보여지는 행을 제한한 결과가 최종적으로 우리가 보게 되는 테이블 입니다.


하나의 SELECT 문을 실행한 결과가 결국 테이블이라면, 이 테이블에 다시 SELECT 문을 적용할 수 있지 않을까요? SELECT 문을 SELECT 내부에서 사용하면 우리가 원하는 다양한 결과를 얻을 수 있습니다. SELECT 문을 통해서 얻어낸 중간 결과 테이블을 Derived Table이라고 부르며, 오늘은 이 중간 결과 테이블을 사용하는 방법 대해서 알아보도록 하겠습니다.


AS

본격적으로 배우기 전에, 결과 테이블의 열이름에 별명(alias)을 붙이는 방법을 알아보도록 합시다. GROUP BY 를 이용해 사용자 테이블에서 나이별 평균 키를 구하는 상황을 가정합시다. 우리는 아래 SQL 을 이용해서 이를 구할 것 입니다.

최종적인 결과값을 살펴보면 평균키의 열 이름이 avg(height) 라고 되어있는 것을 볼 수 있습니다. SQL 에서는 AS(에즈) 키워드를 이용해 결과값의 열 이름을 변경할 수 있습니다. 예를 들어, 평균 키라는 의미에서 avg_height 로 이름을 변경하고 싶다면 아래와 같이 쿼리를 작성하면 됩니다.


SELECT

이제 다시 본론으로 돌아와서, SELECT의 결과를 SELECT하는 방법에 대해서 배워보도록 합시다. 위의 예제를 그대로 사용해서, 사용자 테이블에서 나이별로 평균 키를 구하고 싶다고 가정합시다. 이때 SQL 은 아래와 같습니다.

이 SQL문을 실행했을때 아래와 같이 결과값이 나왔다고 가정합시다. AS 를 사용했기 때문에, 열이름이 변경되된것을 확인해주세요.


여기에서 한 걸음 더 나아가서, 평균키가 170 이상인 나이만 선택하고 싶다고 가정합시다. 위의 테이블을 구하는 SQL을 처음 돌릴때, 아래와 같이 WHERE 조건문을 추가하면 되지 않나 생각할 수 있지만, 그렇지 않습니다. 아래와 같은 SQL 은 키가 170 이상인 사용자를 선택한 후 나이별로 평균 값을 구하기 때문에 전혀 다른 결과값이 도출되게 됩니다. 170 이하 사용자가 평균을 구할 때 모두 빠져서, 전체 평균 값이 높아진 잘 못 된 결과값이 나올 것입니다.


어떻게 하면 될까요? 설명했듯이 위의 쿼리를 통해 구해진 결과값, 즉 나이별 평균 키 데이터 역시 테이블입니다. 이 테이블을 하나의 테이블로 생각하고, 이를 대상으로 SELECT, FROM 그리고 WHERE 조건을 작성하면 됩니다. 괄호 안에 들어가있는 SELECT 문에 집중하세요. 원래 FROM 뒤에 테이블명이 왔던것처럼, 괄호안에 들어가있는 SELECT 문이 결국 하나의 테이블이기 때문에, 아래 쿼리가 동작하게 됩니다.


쿼리가 동작하는 순서를 한번 살펴봅시다. 먼저, 괄호 안에 들어있는 SELECT 문이 먼저 실행되어 중간 결과 테이블을 만들어냅니다. 그 다음 이 중간 결과 테이블을 대상으로 바깥쪽에 위치한 SELECT 문이 실행되어 최종 결과를 보여주게 됩니다.

AS를 사용하는 이유

이 시점에서 AS 키워드를 다룬 이유를 말씀드리겠습니다. 예전 글 SQL 이란 무엇인가 에서 다루었던것처럼, DBMS 는 SQL을 한글자씩 읽으면서 해석합니다. 만약, 미리 정의된 규칙에 벗어나거나 해석하기 어려운 SQL 을 사용자가 요청하면 해석이 불가능합니다.


위의 예제에서 AS 키워드를 사용하지 않고 SQL 을 작성한다면 아래와 같은 쿼리를 작성했을 것입니다. AS가 없는 것을 제외하고는 완전히 동일한 SQL 이라는 점을 다시 한번 확인하세요.

DBMS 에 입장에서는 이 SQL 은 해석하기 매우 어렵습니다. 왜냐하면, 2번째 줄에 위치한 avg(height)는 SQL 입장에서는 함수를 구하라는 의미입니다. 하지만, 위에서 우리는 4번째 줄에서 구한 중간 결과 테이블의 2번째 열, 즉 avg(height)라고 명칭된 열을 선택하고자 2번째 줄에 avg(height)를 입력했습니다. DBMS 입장에서는 2번째 줄의 avg(height)가 중간 결과 테이블의 열을 선택하라는 의미인지 아니면 다시 새롭게 평균 함수를 적용하라는 것인지 이해할 수 없습니다. 


이 문제를 해결하는 방법이 바로 AS 키워드입니다. 열 이름에 미리 정의된 키워드가 들어있을 경우 (여기에서는 avg라는 함수 키워드) 헷갈려하기 때문에 AS를 이용해 키워드가 들어가지 않은 열 이름으로 변경하는 것입니다. 예를 들면, 아래와 같이 avg_height로 중간 결과 테이블의 열 이름을 변경하면 됩니다.


마지막 규칙

여기까지 배운 쿼리는 의미상으로는 아무런 문제가 없습니다. 하지만, 위의 쿼리를 실제로 돌려보면 안타깝게도 아래와 같은 에러가 발생합니다. 

해석을 해보자면 모든 중간 결과 테이블 (derived table)은 자기만의 별명을 가지고 있어야 한다는 에러입니다. 이 에러를 피하기 위해서는 아래와 같이 중간 결과 테이블에 AS 키워드를 이용해서 별명을 붙여주면 됩니다. AS 키워드로 붙여지는 별명은 아무 명칭이나 써도 상관없습니다. 저는 a나 b 알파벳으로 보통 별명을 붙이기 때문에 여기에서는 a라고 붙이도록 하겠습니다.

이렇게 중간 결과 테이블에 별명을 붙이는 이유는 지금 단계에서는 이해할 필요가 없습니다. 단순히 MySQL은 중간 결과 테이블에 반드시 별명을 붙이도록 규칙을 정해놓고 있으며, 에러가 발생하는 것을 피하기 위해서는 중간 결과 테이블에 AS 키워드로 별명을 붙여주면 된다고 이해하시면 됩니다.


마치며

우리가 작성하는 혹은 작성할 수 있는 SQL 이 많이 복잡해진것 같습니다. 중간 결과 테이블의 이론상 설명은 아주 간단합니다. SELECT 문으로 얻어낸 결과도 결국 테이블이니, 데이터베이스 내부 테이블에서 데이터를 가져오는것처럼 SELECT 문으로 얻어낸 테이블에도 SELECT 를 적용할 수 있다는 것입니다.


하지만, 막상 실전에서 사용하려고하면 생각해야 하는 단계가 늘어나 꽤나 난이도가 있는 것 같습니다. 하나의 SELECT 문으로 내가 원하는 결과를 얻을 수 있는지 혹은 SELECT 를 한번 하고 그 다음에 SELECT 를 하면 되는 것인지 판단하는게 쉽지 않기 때문입니다. 이 부분은 계속 연습을 통해서 감을 익히도록 노력해야합니다.



브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari