Search

[SQL] GROUP BY

Tags
Date

개요

앞전의 SELECT에 이어서 이번 포스팅에서는 GROUP BY에 대해 알아보겠습니다. GROUP BY는 SELECT 문에서 사용되는 절 중 하나로, 데이터를 그룹화하고 그룹별로 집계 함수를 사용하여 데이터를 요약할 때 사용됩니다. GROUP BY를 사용하면 특정 컬럼의 값을 기준으로 데이터를 그룹화하여 해당 그룹별로 집계 함수를 적용할 수 있습니다.
GROUP BY도 마찬가지로 기본 형태를 기억해주세요!
SELECT [열] FROM [테이블] GROUP BY [열]

문제

CAR_RENTAL_COMPANY_CAR 테이블에서 '통풍시트', '열선시트', '가죽시트' 중 하나 이상의 옵션이 포함된 자동차가 자동차 종류 별로 몇 대인지 출력하는 SQL문을 작성해주세요. 이때 자동차 수에 대한 컬럼명은 CARS로 지정하고, 결과는 자동차 종류를 기준으로 오름차순 정렬해주세요.
우선 테이블은 다음과 같은 필드로 채워져 있습니다.
SELECT * FROM CAR_RENTAL_COMPANY_CAR;
car_id car_type daily_fee options 1 트럭 102000 주차감지센서,열선시트 2 SUV 148000 주차감지센서,후방카메라 3 세단 55000 스마트키,통풍시트,가죽시트 4 SUV 150000 주차감지센서,스마트키,열선시트,후방카메라,가죽시트 5 SUV 127000 주차감지센서,스마트키 6 트럭 133000 주차감지센서,스마트키 7 승합차 150000 스마트키,통풍시트,열선시트,후방카메라 8 트럭 107000 주차감지센서,통풍시트,열선시트 9 SUV 84000 주차감지센서,스마트키 10 세단 162000 주차감지센서,스마트키,후방카메라 11 승합차 122000 열선시트,후방카메라 12 트럭 142000 후방카메라 13 승합차 144000 네비게이션 14 SUV 77000 주차감지센서,스마트키,열선시트,후방카메라 15 승합차 114000 주차감지센서,통풍시트,후방카메라 16 세단 168000 주차감지센서,열선시트,후방카메라 17 SUV 107000 스마트키,후방카메라 18 SUV 22000 주차감지센서,스마트키,열선시트,후방카메라 19 SUV 79000 주차감지센서,스마트키,열선시트,후방카메라 20 트럭 168000 주차감지센서,통풍시트 21 리무진 250000 주차감지센서,스마트키,통풍시트,후방카메라 22 세단 186000 주차감지센서,스마트키,통풍시트 23 세단 50000 스마트키,네비게이션,열선시트 24 세단 184000 주차감지센서,스마트키,열선시트,후방카메라 25 세단 115000 주차감지센서,열선시트 26 SUV 126000 주차감지센서,통풍시트 27 SUV 23000 주차감지센서,스마트키,통풍시트 28 리무진 298000 주차감지센서,스마트키,네비게이션,열선시트,후방카메라,가죽시트 29 SUV 88000 주차감지센서,후방카메라 30 트럭 140000 주차감지센서,스마트키
Java
복사
결과는 다음과 같은 형태로 출력해야 합니다.
CAR_TYPE
CARS
SUV
2
세단
1
트럭
1
SELECT CAR_TYPE, COUNT(*) AS CARS FROM CAR_RENTAL_COMPANY_CAR WHERE OPTIONS LIKE '%가죽시트%' OR OPTIONS LIKE '%열선시트%' OR OPTIONS LIKE '%통풍시트%'
WHERE OPTIONS IN ('%가죽시트%', '%열선시트%', '%통풍시트%') GROUP BY CAR_TYPE ORDER BY CAR_TYPE ASC;

추가

SELECT NAME, COUNT(NAME) as COUNT FROM ANIMAL_INS GROUP BY NAME HAVING COUNT(NAME) >= 2 ORDER BY NAME;
COUNT( ) 에서 괄호 안에 있는 열이 무엇을 의미하는가?
예를 들어, COUNT(NAME) 하면 NULL을 제외한 행의 개수를 세어줍니다. 위 예제에서는 GROUP BY NAME을 했으므로, 그룹화 된 이름의 개수를 세어주는 것입니다.
HAVINGWHERE은 어떻게 다른가?
HAVING 절과 WHERE 절은 SQL에서 데이터를 필터링하는 데 사용되는 두 가지 절입니다. 그러나 두 절은 목적과 사용되는 위치에서 차이가 있습니다.
WHERE 절:
WHERE 절은 데이터베이스에서 특정 레코드를 선택하기 위해 사용됩니다.
WHERE 절은 일반적으로 SELECT, UPDATE, DELETE 문과 함께 사용됩니다.
WHERE 절은 데이터베이스로부터 레코드를 가져오기 전에 필터링하는 역할을 합니다.
WHERE 절은 주로 테이블의 열과 값을 비교하여 조건을 만족하는 레코드를 선택하는 데 사용됩니다.
SELECT * FROM Students WHERE Age > 20;
SQL
복사
위의 예시에서 WHERE 절은 "Students" 테이블에서 Age 열이 20보다 큰 레코드를 선택합니다.
HAVING 절:
HAVING 절은 집계 함수를 사용하여 그룹화된 데이터를 필터링하기 위해 사용됩니다.
HAVING 절은 GROUP BY 절과 함께 사용되며, 일반적으로 SELECT 문에서 GROUP BY 절을 사용한 이후적용됩니다.
HAVING 절은 GROUP BY를 통해 생성된 그룹의 집계 결과를 필터링하는 역할을 합니다.
HAVING 절은 주로 집계 함수 (예: COUNT, SUM, AVG 등)를 사용하여 그룹의 조건을 검사하는 데 사용됩니다.
SELECT Department, AVG(Salary) AS AvgSalary FROM Employees GROUP BY Department HAVING AVG(Salary) > 50000;
SQL
복사
위의 예시에서 HAVING 절은 "Employees" 테이블에서 Department 별 평균 Salary를 계산한 후, 평균 Salary이 50000보다 큰 그룹을 선택합니다.
요약하면, WHERE 절은 특정 레코드를 선택하는 데 사용되고, HAVING 절은 그룹화된 데이터를 필터링하는 데 사용됩니다. WHERE 절은 데이터를 가져오기 전에 사용되며, HAVING 절은 GROUP BY 이후에 사용됩니다.

예제 문제

09:00부터 19:59까지, 각 시간대별로 입양이 몇 건이나 발생했는지 조회하는 SQL문을 작성해주세요. 이때 결과는 시간대 순으로 정렬해야 합니다.
SELECT DATE_FORMAT(DATETIME, '%H') AS HOUR, COUNT(*) AS COUNT FROM ANIMAL_OUTS WHERE DATE_FORMAT(DATETIME, '%H') BETWEEN '09' AND '19' GROUP BY DATE_FORMAT(DATETIME, '%H') ORDER BY DATE_FORMAT(DATETIME, '%H');
SQL
복사
APPOINTMENT 테이블에서 2022년 5월에 예약한 환자 수를 진료과코드 별로 조회하는 SQL문을 작성해주세요. 이때, 컬럼명은 '진료과 코드', '5월예약건수'로 지정해주시고 결과는 진료과별 예약한 환자 수를 기준으로 오름차순 정렬하고, 예약한 환자 수가 같다면 진료과 코드를 기준으로 오름차순 정렬해주세요.
2022년 5월 예약한 환자 수를 진료과코드 별로 조회하는 문제입니다. 이 문장을 통해 2022년 5월은 WHERE, 진료화코드는 GROUP BY로 나타낼 수 있는 것을 확인할 수 있습니다.
SELECT MCDP_CD AS '진료과코드', COUNT(*) AS '5월예약건수' FROM APPOINTMENT WHERE MONTH(APNT_YMD) = 5 AND YEAR(APNT_YMD) = 2022 GROUP BY MCDP_CD ORDER BY 5월예약건수 ASC, 진료과코드 ASC;
SQL
복사
2022-05-18 10:30:00.000000 다음과 같이 시간이 주어질 때, MONTH(), YEAR()을 통해 날짜에 해당하는 정보를 출력할 수 있습니다.
ORDER BY 적용 시 변경된 테이블 이름에 대해 ‘ ‘ 를 붙이지 않습니다.
상반기 동안 각 아이스크림 성분 타입성분 타입에 대한 아이스크림의 총주문량총주문량이 작은 순서대로 조회하는 SQL 문을 작성해주세요. 이때 총주문량을 나타내는 컬럼명은 TOTAL_ORDER로 지정해주세요.
위 문제를 통해 아이스크림의 성분 타입에 따라 GROUP BY 하는 것을 유추할 수 있으며, 총 주문량이 작은 순서대로 조회하기 때문에 이는 ORDER BY 를 통해 정렬 기준을 정립할 수 있습니다. 이 문제는 주문 정보를 담은 테이블과 아이스크림 성분에 대한 테이블이 존재합니다.
SELECT i.INGREDIENT_TYPE, SUM(f.TOTAL_ORDER) AS TOTAL_ORDER FROM FIRST_HALF AS f JOIN ICECREAM_INFO AS i ON f.FLAVOR = i.FLAVOR GROUP BY i.INGREDIENT_TYPE ORDER BY TOTAL_ORDER;
SQL
복사
우선 두 개의 테이블을 하나로 합쳐주는 작업이 필요합니다. 여기에서는 FLAVOR이 외래 키로 작동하고 있기 때문에 다음과 같은 명령어를 통해 두 테이블을 합쳐줍니다.
SELECT * FROM FIRST_HALF AS F JOIN ICECREAM_INFO AS I ON f.FLAVOR = i.FLAVOR;
SQL
복사
PRODUCT 테이블에서 만원 단위의 가격대 별로 상품 개수를 출력하는 SQL 문을 작성해주세요. 이때 컬럼명은 각각 컬럼명은 PRICE_GROUP, PRODUCTS로 지정해주시고 가격대 정보는 각 구간의 최소금액(10,000원 이상 ~ 20,000 미만인 구간인 경우 10,000)으로 표시해주세요. 결과는 가격대를 기준으로 오름차순 정렬해주세요.
SELECT FLOOR((PRICE) / 10000) * 10000 AS PRICE_GROUP, COUNT(*) AS PRODUCTS FROM PRODUCT GROUP BY FLOOR((PRICE) / 10000) ORDER BY FLOOR((PRICE) / 10000);
SQL
복사
REST_INFO 테이블에서 음식종류별로 즐겨찾기수가 가장 많은 식당의 음식 종류, ID, 식당 이름, 즐겨찾기수를 조회하는 SQL문을 작성해주세요. 이때 결과는 음식 종류를 기준으로 내림차순 정렬해주세요.
SELECT FOOD_TYPE, REST_ID, REST_NAME, FAVORITES FROM REST_INFO WHERE (FOOD_TYPE, FAVORITES) IN (SELECT FOOD_TYPE, MAX(FAVORITES) FROM REST_INFO GROUP BY FOOD_TYPE) ORDER BY FOOD_TYPE DESC;
SQL
복사
SELECT U.USER_ID, U.NICKNAME, SUM(B.PRICE) as TOTAL_SALES FROM USED_GOODS_BOARD B JOIN USED_GOODS_USER U ON B.WRITER_ID = U.USER_ID WHERE B.STATUS LIKE '%DONE%' GROUP BY U.USER_ID, U.NICKNAME HAVING SUM(B.PRICE) >= 700000 ORDER BY TOTAL_SALES ASC
SQL
복사
WITH TotalRentals AS ( SELECT CAR_ID FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY WHERE START_DATE BETWEEN '2022-08-01' AND '2022-10-31' GROUP BY CAR_ID HAVING COUNT(*) >= 5 ) SELECT MONTH(START_DATE) AS MONTH, cr.CAR_ID, COUNT(*) AS RECORDS FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY cr JOIN TotalRentals tr ON cr.CAR_ID = tr.CAR_ID WHERE START_DATE BETWEEN '2022-08-01' AND '2022-10-31' GROUP BY cr.CAR_ID, MONTH(START_DATE) ORDER BY MONTH(START_DATE) ASC, cr.CAR_ID DESC;
SQL
복사