본문 바로가기
혼공학습단 12기

[혼공S] 03 - 2 '좀 더 깊게 알아보는 SELECT 문' 정리

by jaeheon0520 2024. 7. 9.

 

SELECT ~ FROM ~ WHERE는 가장 핵심적인 SQL 문이다. 이에 부가적으로 결과를 정렬하거나, 중복을 제거하거나, 일부만 보여주는 등의 다양한 처리가 필요할 때도 있다. 또 결과를 한 건씩 보는 경우도 있지만 묶음으로 처리해서 봐야 하는 경우도 있다. 이에 대해 살펴보자.

 

SELECT 문에서는 결과의 정렬을 위한 ORDER BY, 결과의 개수를 제한하는 LIMIT, 중복된 데이터를 제거하는 DISTINCT 등을 사용할 수 있다.

 

그리고 GROUP BY 절은 지정한 열의 데이터들을 같은 데이터끼리는 묶어서 결과를 추출한다. 주로 그룹으로 묶는 경우는 합계, 평균, 개수 등을 처리할 때 사용하므로 집계 함수와 함께 사용된다. GROUP BY 절에서도 HAVING 절을 통해 조건식을 추가할 수 있다. HAVING 절은 WHERE 절과 비슷해 보이지만, GROUP BY절과 함께 사용되는 것이 차이점이다.

 

 

ORDER BY 절

SELECT 절의 형식은 다음과 같다. 이 중에서 아직 다루지 않은 ORDER BY와 LIMIT에 대해서 먼저 살펴보고 잠시 후에 GROUP BY, HAVING에 대해서 알아보자.

 

SELECT 열_이름
    FROM 테이블_이름
    WHERE 조건식
    GROUP BY 열_이름
    HAVING 조건식
    ORDER BY 열_이름
    LIMIT 숫자

 

ORDER BY 절은 결과의 값이나 개수에 대해서는 영향을 미치지 않지만, 결과가 출력되는 순서를 조절한다. 다음과 같이 입력하여 실행해보자. 데뷔 일자(debut_date)가 빠른 순서대로 출력되었다.

 

SELECT mem_id, mem_name, debut_date
    FROM member
    ORDER BY debut_date;

 

 

데뷔 일자(debut_date)가 늦은 순서대로 정렬하려면 어떻게 해야 할까? 간단히 제일 뒤에 DESC라고 붙여주면 된다. 기본 값은 ASC인데 Ascending의 약자로 오름차순을 의미하고, DESC는 Descending의 약자로 내림차순을 의미한다.

 

SELECT mem_id, mem_name, debut_date
    FROM member
    ORDER BY debut_date DESC;

 

 

ORDER BY 절과 WHERE 절은 함께 사용할 수 있다. 평균 키(height)가 164 이상인 회원들을 키가 큰 순서대로 조회해보자. 그런데 오류가 발생했다. 이유는 SQL 구문의 순서가 틀렸기 때문이다.

 

SELECT mem_id, mem_name, debut_date, height
    FROM member
    ORDER BY height DESC
    WHERE height >= 164 -- 오류 발생!

 

ORDER BY 절은 WHERE 절 다음에 나와야 한다. 다음과 같이 수정하고 실행해보자.

 

SELECT mem_id, mem_name, debut_date, height
    FROM member
    WHERE height >= 164
    ORDER BY height DESC;

 

 

하지만 한 가지 더 고려할 사항이 있다. 잇지와 트와이스의 평균 키(height)는 167로 동일한데 잇지가 먼저 출력되었다. 트와이스 입장에서는 자신들이 데뷔 일자(debut_date)가 더 빠르므로 먼저 나와야 된다고 생각할 수 있다.

 

정렬 기준은 1개 열이 아니라 여러 개 열로 지정할 수 있다. 우선 첫 번째 지정 열로 정렬한 후에 동일할 경우에는 다음 지정 열로 정렬할 수 있다. 즉, 평균 키가 큰 순서대로 정렬하되, 평균 키가 같으면 데뷔 일자가 빠른 순서로 정렬한다.

 

SELECT mem_id, mem_name, debut_date, height
    FROM member
    WHERE height >= 164
    ORDER BY height DESC, debut_date ASC;

 

 

출력의 개수를 제한: LIMIT

LIMIT는 출력하는 개수를 제한한다. 예를 들어, 회원 테이블(member)을 조회하는데 전체 중 앞에서 3건만 조회할 수 있다.

 

SELECT *
    FROM member
    LIMIT 3;

 

 

 

결과에는 문제가 없지만, 이렇게 아무런 기준 없이 앞에서 3건만 뽑는 경우는 별로 없다. 먼저 정렬한 후 앞에서 몇 건을 추출하는 것이 대부분이다. 예를 들어, 데뷔 일자(debut_date)가 빠른 회원 3건만 추출하려면 다음과 같이 ORDER BY와 함께 사용할 수 있다.

 

SELECT mem_name, debut_date
    FROM member
    ORDER BY debut_date
    LIMIT 3;

 

LIMIT 형식은 LIMIT 시작, 개수이다. 지금과 같이 LIMIT 3만 쓰면 LIMIT 0, 3과 동일하다. 즉 0번째부터 3건이라는 의미이다.

 

필요하다면 중간부터 출력도 가능하다. 다음과 같이 평균 키(height)가 큰 순으로 정렬하되, 3번째부터 2건만 조회할 수 있다.

 

SELECT men_name, height
    FROM member
    ORDER BY height DESC
    LIMIT 3, 2;

 

 

중복된 결과를 제거: DISTINCT

DISTINCT는 조회된 결과에서 중복된 데이터를 1개만 남긴다. 여기서는 회원들의 지역(addr)을 출력해보자.

 

다음 SQL의 결과를 보면 회원이 사는 지역(addr)은 경기, 경남, 서울, 전남, 경북 등 5군데 인것을 확인할 수 있다. 지금은 데이터 건수가 적은데도 중복된 것을 눈으로 골라내기 어렵다.

 

SELECT addr FROM member;

 

 

그래서 앞에서 배운 ORDER BY를 사용해보자. 같은 지역(addr)이 몰려 있어서 아까보다는 세기가 쉽지만 이 역시 데이터 건수가 수만 개라면 종류를 세는 것은 머무 어려울 것이다.

 

SELECT addr FROM member ORDER BY addr;

 

이를 간단하게 하는 것이 DISTINCT 문이다. 열 이름 앞에 DISTINCT를 써주기만 하면 중복된 데이터를 1개만 남기고 제거한다. 유용하게 사용되는 구문이므로 기억해두자.

 

SELECT DISTINCT addr FROM member;

 

 

GROUP BY 절

다시 SELECT 절의 형식을 살펴보자. 이 중에서 아직 다루지 않은 것은 GROUP BY와 HAVING 이다.

 

SELECT 열_이름
    FROM 테이블_이름
    WHERE 조건식
    GROUP BY 열_이름
    HAVING 조건식
    ORDER BY 열_이름
    LIMIT 숫자

 

GROUP BY 절은 말 그대로 그룹으로 묶어주는 역할을 한다. 다음 SQL을 사용하면 market_db의 구매 테이블(buy)에서 회원(mem_id)이 구매한 물품의 개수를 구할 수 있다.

 

SELECT mem_id, amount FROM buy ORDER BY mem_id;

 

회원(mem_id) 별로 여러 건의 물건 구매가 있었고, 각각의 행이 별도로 출력되었다. APN(에이핑크) 회원의 경우에는 1+2+1+1=5개의 물건을 구매했다. 그런데 합계를 이렇게 암산이나 계산기로 계산해야 한다면 MySQL을 사용할 이유가 없다.

 

 

이럴 때는 집계 함수를 사용하면 된다. 집계 함수는 주로 GROUP BY 절과 함께 쓰이며 데이터를 그룹화해주는 기능을 한다.

 

집계 함수

GROUP BY와 함께 주로 사용되는 집계 함수(aggregate function)는 다음 표와 같다.

 

함수명 설명
SUM() 합계를 구한다
AVG() 평균을 구한다
MIN() 최소값을 구한다
MAX() 최대값을 구한다
COUNT() 행의 개수를 센다
COUNT(DISTINCT) 행의 개수를 센다(중복은 1개만 인정)

 

각 회원(mem_id) 별로 구매한 개수(amount)를 합쳐서 출력하기 위해서는 집계 함수인 SUM()과 GROUP BY 절을 사용하면 된다. 즉, GROUP BY로 회원별로 묶어준 후에 SUM() 함수로 구매한 개수를 합치면 된다. 

SELECT mem_id, SUM(amount) FROM buy GROUP BY mem_id;

 

결과 열의 이름 부분에 함수 이름이 그대로 나왔다.

 

 

앞에서 배운 Alias을 사용해서 다음과 같이 결과를 보기 좋게 만들 수 있다.

 

SELECT mem_id 회원아이디, SUM(amount) "총 구매 개수"
    FROM buy
    GROUP BY mem_id;

 

 

이번에는 회원이 구매한 금액의 총합을 출력해보자. 구매한 금액은 가격 (price) * 수량 (amount)이다. 역시 합계는 SUM()을 사용하면 된다.

 

SELECT mem_id "회원 아이디", SUM(price*amount) "총 구매 금액"
    FROM buy
    GROUP BY mem_id;

 

 

전체 회원이 구매한 물품 개수(amount)의 평균을 구해보자. 즉, 회원이 한 번 구매할 때마다 평균 몇 개를 구매하는지 알아보는 것이다.

 

SELECT AVG(amount) "평균 구매 개수" FROM buy;

 

평균 구매 개수의 결과는 3.0개이다.

 

이번에는 각 회원이 한 번 구매 시 평균 몇 개를 구매했는지 알아보자. 회원(mem_id) 별로 구해야 하므로 GROUP BY를 사용하면 된다.

 

SELECT mem_id, AVG(amount) "평균 구매 개수"
    FROM buy
    GROUP BY mem_id;

 

 

이번에는 회원 테이블(member)에서 연락처가 있는 회원의 수를 카운트해보자.

 

우선 전체 회원 수를 카운트 해보자.

SELECT COUNT(*) FROM member;

 

연락처가 있는 회원만 카운트하려면 국번(phone1) 또는 전화번호(phone2)의 열 이름을 지정해야 한다. 그러면 NULL 값인 항목은 제외하고 카운트하여 결국 연락처가 있는 회원의 인원만 나온다.

 

SELECT COUNT(phone1) "연락처가 있는 회원" FROM member;

 

예상한 대로 8명이 나왔다.

 

 

HAVING 절

앞에서 살펴보았던 SUM()으로 회원(mem_id) 별 총 구매액을 구해보자.

 

SELECT mem_id "회원 아이디", SUM(price*amount) "총 구매 금액"
    FROM buy
    GROUP BY mem_id;

 

 

결과 중에서 총 구매액이 1000 이상인 회원에게만 사은품을 증정하려면 어떻게 해야할까? 아마도 조건을 포함하는 WHERE 절을 생각했을 것이다. 그런데 다음과 같이 실행해보니 오류가 발생한다. 오류 메시지를 보면 집계 함수는 WHERE절에 나타낼 수 없다는 내용이다.

 

SELECT mem_id "회원 아이디", SUM(price*amount) "총 구매 금액"
    FROM buy
    WHERE SUM(price*amount) > 1000;
    GROUP BY mem_id;

 

이럴 때 WHERE 대신에 사용되는 것이 HAVING 절이다. HAVING은 WHERE와 비슷한 개념으로 조건을 제한하는 것이지만, 집계 함수에 대해서 조건을 제한하는 것이라고 생각하면 된다. 그리고 HAVING 절은 꼭 GROUP BY 절 다음에 나와야 한다.

 

SELECT mem_id "회원 아디디", SUM(price*amount) "총 구매 금액"
    FROM buy
    GROUP BY mem_id
    HAVING SUM(price*amount) > 1000;

 

 

만약 총 구매액이 큰 사용자부터 나타내려면 ORDER BY를 사용하면 된다.

 

SELECT mem_id "회원 아이디", SUM(price*amount) "총 구매 금액"
    FROM buy
    GROUP BY mem_id
    HAVING SUM(price*amount) > 1000
    ORDER BY SUM(price*amount) DESC;

 

 

이로써 SELECT 문과 관련된 기본적인 SQL의 형식은 모두 살펴보았다.

 

핵심 포인트

  • ORDER BY는 결과가 출력되는 순서를 조절한다. 오름차순인 ASC와 내림차순인 DESC 중 선택할 수 있다.
  • LIMIT는 출력하는 개수를 제한하며, 주로 ORDER BY와 함께 사용한다
  • DISTINCT는 조회된 결과에서 중복된 것은 1개만 남기며, 열 이름 앞에 붙여주면 된다
  • GROUP BY는 데이터를 그룹으로 묶어주는 기능을 한다
  • HAVING은 집계 함수와 관련된 조건을 제한하며, GROUP BY 다음에 나온다

오늘 하루도 쌓였다!