데이터 분석/DB & SQL

[SQL] data.world tutorial SQL CASE 예제 풀이

haloaround 2020. 5. 2. 18:12

컬럼에 대해서 CASE 분기 태울 때 활용한다. 

https://docs.data.world/documentation/sql/concepts/intermediate/CASE.html

 

CASE

Learn about the CASE expression in this SQL tutorial. Visit for a full course on learning the basics of SQL.

docs.data.world

 

CASE 의 활용

CASE is a general conditional expression that allows you to 
- test data for equality with a specified value,  특정값과 동치여부 확인
- partition data into ranges,  데이터를 범위에 따라 나눔(파티션) 
- or perform any other conditional check against the data. 조건문 수행

 

Simple Syntax
대상필드가 모두 동일할 때 요렇게 간단하게 써도 된다.

CASE 대상필드
WHEN a THEN A 
WHEN b THEN B (...) 
ELSE C (opt, if omitted null)
END

 

General Syntax
하지만 현실적으로는 여러 컬럼에 대해 조건을 체크할 가능성이 높으므로 아래와 같이 처리하는 것이 보편적이다. 

CASE 
WHEN a THEN A
WHEN b THEN B (...) 
ELSE c (opt, if omitted null)
END

A, B ...  WHEN THEN 문 순서대로 수행한다. 
ELSE 는 생략 가능하며, WHEN 조건에 모두 부합하지 않고 ELSE 문이 생략되면 null 로 리턴한다. 
ELSE 는 생략 가능은 하지만, 명시성을 위해 기입해주는 것이 좋다. 

 


1. 요구사항 검토

Write a query against the observations_cleaned table using the general CASE expression

- 데이터 소스: observations_cleaned 

 

to return the patient and description columns, the average of the value column, and unit column along with a new column labeled BMI category.

- 데이터 결과 컬럼: patient, description, avg(value), unit, BMI category

 

The results are only for the records where the description is Body Mass Index.

- 데이터 셋 조건: description = "Body Mass Index"

 

The entries in the BMI category column should be Underweight for values under 18.5, Healthy for values from 18.5 to 24.9, Overweight for values of 25-29.9, and Obese for values over 30.

- 컬럼 BMI category 카테고리 범주화: CASE 문

 

Category 의 대표: BMI

 

2. 데이터셋 확인

observations_cleaned 테이블을 확인한다. 

SELECT * FROM observations_cleaned
WHERE description = "Body Mass Index" -- 7296

SELECT DISTINCT patient FROM observations_cleaned
WHERE description = "Body Mass Index" -- 1099

SELECT DISTINCT units FROM observations_cleaned
WHERE description = "Body Mass Index" -- 1, kg/m^2 only

1099 명의 환자에 대해 BMI 지표는 7296 번 측정되었다. 한 환자에게도 BMI 를 여러번 측정했다는 점을 알 수 있다.
BMI 만 추출했으므로 description = "Body Mass Index", units = "kg/m^2" 로 동일하다.

 

3. 쿼리 구조 검토

to return the patient and description columns, the average of the value column, and unit column along with a new column labeled BMI category.

- AVG 값이 필요하니 value 에 대한 평균값 집계 GROUP BY 가 필요하다. 
아마도 집계 기준은 patient 로 추정된다. 

- AVG 외 나머지 컬럼도 집계결과로 편입시켜서 집계한다. 
description, units 는 저 집계대상 데이터셋의 모든 값이 동일한 값이다: Body Mass Index, cm/m^2 
그래도 추가해달라고 요청했으니, String 에 대한 집계함수로 MAX 처리한다. (문자열도 알파벳 순서 기준으로 MIN/MAX 집계함수를 수행할 수 있다.) 

- BMI category 범주화를 해야하니 CASE 문이 필요하다. 

 

4. 쿼리 작성

SELECT patient,
MAX(description),
AVG(value) AS `Avg BMI`,
MAX(units),
CASE
WHEN value < 18.5 THEN "Underweight"
WHEN value >= 18.5 AND value < 25 THEN "Healthy"
WHEN value >= 25 AND value < 30 THEN "Overweight"
WHEN value >= 30 THEN "Obese"
END AS `BMI category`

FROM observations_cleaned
WHERE description = "Body Mass Index"

GROUP BY patient, `BMI category`

 

그런데 노랑 알럿이 뜬다.
- Field of aggregated query neither grouped nor aggregated: line 5, column 8 --> CASE 문

GROUP BY 집계를 활용하면, 결과 데이터셋에 집계기준 (grouped) 이거나 집계결과 (aggregated) 이거나 둘 중 하나이기를 권장한다.

저 Body Mass Index 는 집계 기준일까? 결과일까? 사용자한테 한번 더 물어보자. 환자마다 여러번 BMI 를 측정했고, BMI 카테고리가 변경될 수 있으므로, 집계기준으로 해달라는 요청을 추가로 받았다.  GROUP BY 기준으로 BMI category 를 추가한다. 

 


 

요구사항은 정말 한 문장으로 압축되기 힘들어 보인다.  (심지어 튜토리얼 조차도 명확하지 않다니) 
앞으로 사용자가 쿼리 요구사항을 제대로 안 줘도 너무 원망하지는 말아야겠다. ㅇ__ㅇ;;