CS/DB

[혼공SQL] SQL 기본 문법 SELECT

F12:) 2024. 1. 10. 10:24

3-1에서 다룬 SELECT문의 키워드는 WHERE였다. 이제 더욱 다양한 작업을 위해 사용되는 GROUP BY, HAVING, ORDER BY, LIMIT에 대해서 알아보자.

 

 

   ORDER BY 절

ORDER BY는 결과의 값이나 개수에 대해서는 영향을 미치지 않지만 결과가 보여지는 순서에 영향을 준다.

 

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

이렇게 되면 member 테이블에서 mem_id, mem_name, debut_date를 뽑아오는데, debut_date가 가장 빠른 순서대로 출력된다.

 

기본적으로 ORDER BY에서는 ASC와 DESC 키워드로 오름차순, 내림차순을 조절할 수 있다. 기본값은 ASC이며 DESC 즉, 내림차순을 원한다면 아래와 같이 작성한다.

 

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

 

그렇다면 이제 WHERE와 ORDER BY를 함께 써보자. 주의해야할 것이 있는데, 바로 키워드의 순서이다. 앞서 다룬 SELECT의 구문 순서를 다시 확인해보자.

 

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

 

WHERE와 ORDER BY의 순서를 보면, WHERE가 ORDER BY보다 먼저 나와야한다.

 

이 점을 고려하여 아래와 같이 쿼리문 작성이 가능하다.

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

키가 164 이상인 데이터를 보아 키순으로 내림차순 정렬한 모습을 볼 수 있다.

 

추가적으로 이런 상황도 고려해보자. 만약 키가 동일한 데이터가 두 개 있다. 이 두 개의 정렬 순서를 정해야한다면 어떻게 SQL문을 짜야할까? 예를 들면 키가 동일한 상황에서는 debut_date의 내림차순으로 정렬하고 싶을 때 말이다. 이럴 때는 아래와 같이 작성한다.

 

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

이런 식으로 작성하게 되면 우선 적으로 height로 내림차순 정렬된 후, debut_date로 오름차순 정렬이 되어 height가 동일한 값을 갖는다면 debut_date로 정렬되게 될 것이다.

 

   출력 개수 제한하기: LIMIT

LIMIT는 결과의 출력 개수를 제한한다. 구문 순서는 가장 아래에 위치하게 되고, 'LIMIT 시작, 개수'로 작성할 수 있다. 시작 인덱스부터 개수만큼 뽑아온다는 뜻이다. 'LIMIT 개수'의 형식으로도 작성할 수 있는데 이 때는 시작이 0이 된다.

 

SELECT mem_name, debut_date
	FROM member
    ORDER BY debut_date
    LIMIT 3; -- 시작을 지정하지 않았으니 처음부터 3개를 뽑아온다.

 

SELECT mem_name, height
	FROM member
    ORDER BY height DESC
    LIMIT 3, 2; -- 시작을 지정하였다. 3번째 인덱스부터 2개를 뽑아온다.

 

 

인덱스의 시작은 언제나 0부터라는 것을 잊지 말자.

 

추가적으로 LIMIT 시작, 개수LIMIT 개수 OFFSET 시작이라고 작성할 수도 있다.

 

   중복을 허용하지 않는 DISTINCT

DISTINCT는 중복된 데이터를 1개만 남긴다.

 

SELECT DISTINCT addr FROM member;

위와 같이 열 이름 앞에 쓰이며, addr은 이제 중복된 결과가 나온다면 1개만 나타나게 될 것이다.

 

   GROUP BY 절

말 그대로 그룹화 기능을 담당한다. 예를 들어, 상품 구매 리스트가 있다고 해보자. 해당 상품 구매 목록에서 각 사용자별로 얼만큼의 금액을 썻는지 궁금하다. 아래와 같은 결과를 원할 것이다.

회원 아이디 총 구매 금액
APN 295
BLK 1210
GRL 75
MMU 1950

 

하지만 지금까지 다룬 SQL 문으로는 해당 결과처럼 만들 수 없다. 그래서 우리는 GROUP BY를 사용한다. 또한 GROUP BY는 집계 함수와 같이 쓰이는데, 사용되는 집계 함수는 아래와 같다.

 

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

 

이러한 집계함수를 이용하여 아래와 같은 쿼리문을 작성할 수 있다.

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

그러면 아래와 같은 테이블이 나온다.

mem_id SUM(price*amount)
APN 295
BLK 1210
GRL 75
MMU 1950

 

총 구매금액을 나타내었지만, 열 이름을 수정하고 싶다. 이 때, alias(별칭)을 사용한다. 사용방법은 간단하며 아래와 같다.

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

 

단순히 열 뒤에 원하는 이름을 지정해주면 된다.

 

 

다른 집계함수인 AVG, COUNT 등도 마찬가지인데, 여기서 COUNT는 NULL이 아닌 데이터의 개수를 센다는 것에 주의하자. 

즉, COUNT(*)모든 열의 값이 NULL인 데이터를 무시하지만 COUNT(phone1)phone1 열의 값이 NULL인 데이터를 세지 않는 것이다.

 

 

   HAVING 절

앞서 구한 회원별 구매 총액에서 1000을 넘어가는 데이터만 조회하고 싶을 때 어떻게 할까? 사용했던 WHERE를 또 사용해야할까? 그렇지 않다. GROUP BY를 사용했다면 WHERE가 아닌 HAVING을 사용한다. 아래와 같다.

 

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;