업무 필요한 문자 포맷이 다를 때, SQL로 가공하기 (REPLACE, SUBSTRING, CONCAT)
✔️ Query 결과를 바로 사용할 수 있도록 문자 데이터의 형태를 바꿔봅시다
- 1) Query 결과를 바로 사용할 수 없는 경우
💡 데이터를 조회하다보면, Query 결과를 그대로 이용하지 못하는 경우가 있어요.
아마 실습을 하면서 아래의 경우를 한 번쯤은 생각해봤을 텐데요, 한 번 각각의 케이스와 해결 방법을 알아봅시다
- 데이터를 보니 잘못된 값이 있어요. 이전에 사용하던 값이어서 다른 문자로 수정을 해줘야하는데, 하나하나 수동으로 하기는 너무 많아서 SQL 로 바꿀 수 있을까요?
- 저는 주소 전체가 아닌 ‘시도’ 정보만 필요해요. 서울의 통계만 구하고 싶은데, 전체 주소가 아닌 ‘서울’ 로 문자를 변경할 수는 없을까요?
- 저는 보고서를 작성할 때 사업장 명과 함께 지역이 같이 나와야해요. ‘사업장 [지역]’ 과 같은 형태로 문자 포맷을 변경할 수 있을까요?
- 2) 특정 문자를 다른 문자로 바꾸기 (실습 포함)
👉 바뀐 상점 이름, 지역 이름 한 번에 SQL 로 바꿀 수 있습니다
- SQL 에서는 특정 문자를 다른 것으로 바꿀 수 있는 기능을 제공합니다.
- 예시1) 최근에 상점 이름이 바뀌었지만 과거 데이터에는 옛날 이름으로 저장되어있어요
- 예시2) 예전에 ‘문곡리’ 라는 지명이 ‘문가리’ 로 바뀌었어요
- 함수명 : replace
- 사용 방법
```sql
replace(바꿀 컬럼, 현재 값, 바꿀 값)
```
- [실습1]
(식당 명의 ‘Blue Ribbon’ 을 ‘Pink Ribbon’ 으로 바꾸기)
- [코드스니펫] Replace 예시
```sql
select restaurant_name "원래 상점명",
replace(restaurant_name, 'Blue', 'Pink') "바뀐 상점명"
from food_orders
where restaurant_name like '%Blue Ribbon%'
```
- [실습2]
(주소의 ‘문곡리’ 를 ‘문가리’ 로 바꾸기)
```sql
select addr "원래 주소",
replace(addr, '문곡리', '문가리') "바뀐 주소"
from food_orders
where addr like '%문곡리%'
```
- 3) 원하는 문자만 남기기 (실습 포함)
👉 전체 데이터가 아닌 특정 문자만 필요할 때, SQL 로 필요한 부분만 조회할 수 있습니다
- SQL 에서는 특정 문자만 골라서 조회할 수 있는 기능을 제공합니다
- 예시) 전체 주소에서 앞부분인 ‘시도’ 부분만 필요해요
- 함수명 : substring (substr)
- 사용 방법
```sql
substr(조회 할 컬럼, 시작 위치, 글자 수)
```
- [실습]
(서울 음식점들의 주소를 전체가 아닌 ‘시도’ 만 나오도록 수정)
- [코드스니펫] substring 예시
```sql
select addr "원래 주소",
substr(addr, 1, 2) "시도"
from food_orders
where addr like '%서울특별시%'
```
- 4) 여러 컬럼의 문자를 합치기 (실습 포함)
👉 원하는 문자가 여러 컬럼에 있을 때, 하나로 합쳐서 업무에 필요한 형태로 만들 수 있습니다
- SQL 에서는 여러 컬럼의 값을 하나로 합칠 수 있는 기능을 제공합니다.
- 예시) 서울시에 있는 음식점은 ‘[서울] 음식점명’ 이라고 수정하고 싶어요
- 함수명 : concat
- 사용 방법
```sql
concat(붙이고 싶은 값1, 붙이고 싶은 값2, 붙이고 싶은 값3, .....)
```
- 붙일 수 있는 문자의 종류
- 컬럼
- 한글
- 영어
- 숫자
- 기타 특수문자
- [실습]
(서울시에 있는 음식점은 ‘[서울] 음식점명’ 이라고 수정)
- [코드스니펫] Concat 예시
```sql
select restaurant_name "원래 이름",
addr "원래 주소",
concat('[', substring(addr, 1, 2), '] ', restaurant_name) "바뀐 이름"
from food_orders
where addr like '%서울%'
```
조건에 따라 포맷을 다르게 변경해야한다면 (IF, CASE)
✔️ 조건에 따라 다른 연산을 하는 방법을 알아봅시다
- 1) Group by 처럼 조건도 카테고리별로 줄 수 있을까?
👉 범주별로 값을 구할 때는 group by 를 썻죠.
범주별로 다른 연산 (계산, 문자 바꾸기) 을 적용할 수도 있을까요?
👉 SQL 은 조건에 따라 연산을 적용할 수 있는 기능을 제공합니다
’내가 원하는 범주’ 를 조건으로 주고, 해당 범주에 적용하고 싶은 것을 지정해 주는 방식입니다
💡 개념을 이해하기 어렵다면 아래의 예시를 참고해봅시다
- 음식 타입을 ‘Korean’ 일 때는 ‘한식’, ‘Korean’ 이 아닌 경우에는 ‘기타’ 라고 지정하고 싶어요
- 주소의 시도를 ‘경기도’ 일때는 ‘경기도’, 아닐 때는 앞의 두 글자만 사용하고 싶어요
- 음식 단가를 주문 수량이 1일 때는 음식 가격, 주문 수량이 2개 이상일 때는 음식가격/주문수량 으로 지정하고 싶어요
- 2) 조건에 따라 다른 방법을 적용하고 싶을 때 - If 문 기초 (실습 포함)
👉 조건을 지정해주는 가장 기초 문법은 ‘If’ 문입니다 (엑셀의 기능과 유사합니다)
- IF 문은 원하는 조건에 충족할 때 적용할 방법과 아닌 방법을 지정해 줄 수 있습니다
- 예시) 음식 타입을 ‘Korean’ 일 때는 ‘한식’, ‘Korean’ 이 아닌 경우에는 ‘기타’ 라고 지정하고 싶어요
- 함수명 : if
- 사용 방법
```sql
if(조건, 조건을 충족할 때, 조건을 충족하지 못할 때)
```
- [실습1]
음식 타입을 ‘Korean’ 일 때는 ‘한식’, ‘Korean’ 이 아닌 경우에는 ‘기타’ 라고 지정
- [코드스니펫] If문 예시
```sql
select restaurant_name,
cuisine_type "원래 음식 타입",
if(cuisine_type='Korean', '한식', '기타') "음식 타입"
from food_orders
```
- [실습2]
02. 번 실습에서 ‘문곡리’ 가 평택에만 해당될 때, 평택 ‘문곡리’ 만 ‘문가리’ 로 수정
- [코드스니펫] If문 예시2
```sql
select addr "원래 주소",
if(addr like '%평택군%', replace(addr, '문곡리', '문가리'), addr) "바뀐 주소"
from food_orders
where addr like '%문곡리%'
```
- [실습3]
03. 번 실습에서 잘못된 이메일 주소 (gmail) 만 수정을 해서 사용
- [코드스니펫] If문 예시3
```sql
select substring(if(email like '%gmail%', replace(email, 'gmail', '@gmail'), email), 10) "이메일 도메인",
count(customer_id) "고객 수",
avg(age) "평균 연령"
from customers
group by 1
```
- 3) 조건을 여러가지 지정하고 싶을 때 - Case 문 기초 (실습 포함)
👉 조건을 지정하다보면, 두 개 이상 지정을 해야 할 경우가 생깁니다.
이 때는 case 문을 이용하여 여러번의 if 문을 적용 한 효과를 낼 수 있습니다
- Case 문은 각 조건별로 적용 할 값을 지정해 줄 수 있습니다.
- 조건별로 지정을 해주기 때문에 아래와 같이 if 문을 여러번 쓴 효과를 낼 수 있습니다.
case(조건1, 값1, case(조건2, 값2, 값3))
- 예시) 음식 타입을 ‘Korean’ 일 때는 ‘한식’, ‘Japanese’ 혹은 ‘Chienese’ 일 때는 ‘아시아’, 그 외에는 ‘기타’ 라고 지정
- 함수명 : case
- 사용 방법
```sql
case when 조건1 then 값(수식)1
when 조건2 then 값(수식)2
else 값(수식)3
end
```
- [실습1]
음식 타입을 ‘Korean’ 일 때는 ‘한식’, ‘Japanese’ 혹은 ‘Chienese’ 일 때는 ‘아시아’, 그 외에는 ‘기타’ 라고 지정
```sql
select restaurant_name,
cuisine_type AS "원래 음식 타입",
case when (cuisine_type='Korean') then '한식'
else '기타'
end as " 음식 타입"
from food_orders
```
- [실습2]
음식 단가를 주문 수량이 1일 때는 음식 가격, 주문 수량이 2개 이상일 때는 음식가격/주문수량 으로 지정
*위와 같은 식은 if 로도 쓸 수 있죠! 한 번 연습해보시는 것을 추천합니다!
- [코드스니펫] Case When 실습1
```sql
select order_id,
price,
quantity,
case when quantity=1 then price
when quantity>=2 then price/quantity end "음식 단가"
from food_orders
```
- [실습3]
주소의 시도를 ‘경기도’ 일때는 ‘경기도’, ‘특별시’ 혹은 ‘광역시’ 일 때는 붙여서, 아닐 때는 앞의 두 글자만 사용
- [코드스니펫] Case When 실습2
```sql
select restaurant_name,
addr,
case when addr like '%경기도%' then '경기도'
when addr like '%특별%' or addr like '%광역%' then substring(addr, 1, 5)
else substring(addr, 1, 2) end "변경된 주소"
from food_orders
```
- 4) 조건을 사용할 수 있는 경우 알아보기
💡 조건문, 유용해보이기는 하지만 어디에 사용할 수 있을지 궁금하다면!
활용할 수 있는 케이스를 살펴봅시다
- 새로운 카테고리 만들기
- 음식 타입과 같이 새로운 카테고리를 만들 수 있습니다.
- `한국 음식, 아시아 음식, 미국 음식, 유럽 음식` 이런 식의 새로운 cuisine_category 를 생성할 수 있죠
- 고객들의 분류도 만들 수 있습니다.
- `10대 여성, 10대 남성, 20대 여성, 20대 남성 등`, 이런 식의 성별과 나이별로 새로운 고객 군 카테고리를 생성할 수 있죠
- 연산식을 적용할 조건 지정하기
- 수수료를 계산할 때 흔히들 현금 사용, 카드사용을 나누고는 하죠
- 현금일 때의 수수료율과 카드일 때의 수수료율이 다르다면, 연산식을 만들 때 if 문 혹은 case 문으로 각각 다른 수수료율 혹은 수수료 계산 방식을 적용할 수 있습니다
- 다른 문법 안에서 적용하기
- if, case 문 안에 다른 문법이나 연산을 넣을 수도 있지만, 다른 문법 안에 조건문을 넣을 수도 있습니다
- 예를 들어 concat 문으로 여러 컬럼을 합칠 때, rating 이 있을 때는 rating 을 넣어주고 없을 때는 아무것도 넣지 않도록, concat 안에 if 문을 넣어줄 수 있죠
[실습] SQL로 간단한 User Segmentation 해보기
✔️ 새로운 카테고리 만들기 - 조건문과 수식을 이용하여 간단한 User Segmentation 을 해봅시다
- 1) [실습] 10세 이상, 30세 미만의 고객의 나이와 성별로 그룹 나누기 (이름도 같이 출력)
- Query 를 적기 전에 흐름을 정리해보기
- 어떤 테이블에서 데이터를 뽑을 것인가
- 어떤 컬럼을 이용할 것인가
- 어떤 조건을 지정해야 하는가
- 어떤 함수 (수식) 을 이용해야 하는가
- 1.Query 를 적기 전에 흐름을 정리해보기 (해답)
- 어떤 테이블에서 데이터를 뽑을 것인가 → 고객 테이블
- 어떤 컬럼을 이용할 것인가 → 이름, 나이, 성별
- 어떤 조건을 지정해야 하는가 → 나이가 10세 이상, 30세 미만
- 어떤 함수 (수식) 을 이용해야 하는가 → 조건문
- 2.구문으로 만들기
- 어떤 테이블에서 데이터를 뽑을 것인가
- 어떤 컬럼을 이용할 것인가
- 어떤 조건을 지정해야 하는가
- 어떤 함수 (수식) 을 이용해야 하는가
- 2.구문으로 만들기 (해답)
- 어떤 테이블에서 데이터를 뽑을 것인가 → from customers
- 어떤 컬럼을 이용할 것인가 → name, age, gender
- 어떤 조건을 지정해야 하는가 → where age between 10 and 29
- 어떤 함수 (수식) 을 이용해야 하는가 → case when …. end
- 3.전체 구조로 합치기
select name,
age,
gender,
case when (age between 10 and 19) and gender='male' then "10대 남자"
when (age between 10 and 19) and gender='female' then "10대 여자"
when (age between 20 and 29) and gender='male' then "20대 남자"
when (age between 20 and 29) and gender='female' then "20대 여자" end "그룹"
from customers
where age between 10 and 29
- 2) [실습] 음식 단가, 음식 종류 별로 음식점 그룹 나누기 (Korean = 한식
Japanese, Chinese, Thai, Vietnamese, Indian = 아시아식
그외 = 기타) (가격 = 5000 미만, 5000 이상 15000 미만, 15000 이상)
- Query 를 적기 전에 흐름을 정리해보기
- 어떤 테이블에서 데이터를 뽑을 것인가
- 어떤 컬럼을 이용할 것인가
- 어떤 조건을 지정해야 하는가
- 어떤 함수 (수식) 을 이용해야 하는가
- 1.Query 를 적기 전에 흐름을 정리해보기 (해답)
- 어떤 테이블에서 데이터를 뽑을 것인가 → 주문 테이블
- 어떤 컬럼을 이용할 것인가 → 주문 금액, 주문 수량, 음식 종류
- 어떤 조건을 지정해야 하는가 → X
- 어떤 함수 (수식) 을 이용해야 하는가 → 조건문
- 2.구문으로 만들기
- 어떤 테이블에서 데이터를 뽑을 것인가
- 어떤 컬럼을 이용할 것인가
- 어떤 조건을 지정해야 하는가
- 어떤 함수 (수식) 을 이용해야 하는가
- 2.구문으로 만들기 (해답)
- 어떤 테이블에서 데이터를 뽑을 것인가 → from food_orders
- 어떤 컬럼을 이용할 것인가 → price, quantity, cuisine_type
- 어떤 조건을 지정해야 하는가 → X
- 어떤 함수 (수식) 을 이용해야 하는가 → case when …. end
- 3.전체 구조로 합치기
- [코드스니펫] 4-5 실습2
select restaurant_name,
price/quantity "단가",
cuisine_type,
order_id,
case when (price/quantity <5000) and cuisine_type='Korean' then '한식1'
when (price/quantity between 5000 and 15000) and cuisine_type='Korean' then '한식2'
when (price/quantity > 15000) and cuisine_type='Korean' then '한식3'
when (price/quantity <5000) and cuisine_type in ('Japanese', 'Chinese', 'Thai', 'Vietnamese', 'Indian') then '아시아식1'
when (price/quantity between 5000 and 15000) and cuisine_type in ('Japanese', 'Chinese', 'Thai', 'Vietnamese', 'Indian') then '아시아식2'
when (price/quantity > 15000) and cuisine_type in ('Japanese', 'Chinese', 'Thai', 'Vietnamese', 'Indian') then '아시아식3'
when (price/quantity <5000) and cuisine_type not in ('Korean', 'Japanese', 'Chinese', 'Thai', 'Vietnamese', 'Indian') then '기타1'
when (price/quantity between 5000 and 15000) and cuisine_type not in ('Korean', 'Japanese', 'Chinese', 'Thai', 'Vietnamese', 'Indian') then '기타2'
when (price/quantity > 15000) and cuisine_type not in ('Korean', 'Japanese', 'Chinese', 'Thai', 'Vietnamese', 'Indian') then '기타3' end "식당 그룹"
from food_orders
SQL문에 문제가 없는 것 같은데 왜 오류가 나나요_ (Data Type 오류 해결하기)
✔️ 숫자 계산이나 문자 가공 시 자주 발생하는 오류를 알아봅시다.
- 문자/숫자 계산을 했더니 오류가 났어요
👉 SQL 문을 회사에서 써봤는데요, avg, substring 등 함수를 썼더니 에러메세지에 ‘data type’ 단어가 뜨면서 실행되지 않아요
- 우리가 실습하는 Mysql 과 다르게, 다른 SQL 문법에서는 data type 이 다를 때 연산이 되지 않을 수 있습니다.
- 1) 번에서 봤던 예시를 보면, rating 은 숫자가 포함되어 있지만 문자 형으로 저장이 되어있습니다
(출력 결과 컬럼명 옆의 ‘ABC’ 혹은 ‘123’ 을 확인해주세요. ‘ABC’ 는 문자로 저장이 되어있다는 의미입니다.)
- 따라서 문자, 숫자를 혼합하여 함수에 사용 할 때에는 데이터 타입을 변경해주어야 합니다
```sql
--숫자로 변경
cast(if(rating='Not given', '1', rating) as decimal)
--문자로 변경
concat(restaurant_name, '-', cast(order_id as char))
```