rubus0304 님의 블로그
[데이터 분석 2일차 ②] (Replace, Substring, Concat, 문자데이터 바꾸기 , IF, Case, User Segmentation, 오류해결) 본문
[데이터 분석 2일차 ②] (Replace, Substring, Concat, 문자데이터 바꾸기 , IF, Case, User Segmentation, 오류해결)
rubus0304 2024. 10. 1. 21:45Replace / Substring (Substr) / Concat / 문자데이터 바꾸고 Group by) / If / Case (when~then, else, end) / User Segmentation / 오류해결
1. 특정문자를 다른 문자로 바꾸기
Replace(바꿀 컬럼, 현재 값, 바꿀 값)
ex) 식당 명의 ‘Blue Ribbon’ 을 ‘Pink Ribbon’ 으로 바꾸기
select restaurant_name as "원래 상점명",
replace(restaurant_name, 'Blue', 'Pink') as "바뀐 상점명"
from food_orders
where restaurant_name like '%blue Ribbon%'
ex) 주소의 ‘문곡리’ 를 ‘문가리’ 로 바꾸기
select addr as "원래 주소",
replace(addr, '문곡리', '문가리') as "바뀐 주소"
from food_orders
where addr like '%문곡리'
2. 원하는 문자만 남기기
Substr(조회 할 컬럼, 시작 위치, 글자 수)
ex) 서울 음식점들의 주소를 전체가 아닌 ‘시도’ 만 나오도록 수정
select addr "원래주소",
substr(addr,1,2) "시도"
from food_orders
where addr like '%서울특별시%'
3. 여러 컬럼의 문자를 합치기
Concat(붙이고 싶은 값1, 붙이고 싶은 값2, 붙이고 싶은 값3, .....)
ex) 서울시에 있는 음식점은 ‘[서울] 음식점명’ 이라고 수정
select restaurant_name "원래 이름",
addr "원래 주소",
concat('[', substr(addr,1,2), ']', restaurant_name) "바뀐 이름"
from food_orders
where addr like '%서울특별시%'
**concat (문자는 ' ', 함수 붙일 땐 ' ' 제외)
4. 문자데이터 바꾸고 Group by
ex) 서울 지역의 음식 타입별 평균 음식 주문금액 구하기 (출력 : ‘서울’, ‘타입’, ‘평균 금액’)
select substr(addr,1,2) "시도",
cuisine_type "음식 종류",
avg(price) "평균금액"
from food_orders
where addr like '%서울특별시%
group by substr(addr,1,2), cuisine_type (= group by 1, 2 (1번째, 2번째 컬럼))
ex) 이메일 도메인별 고객 수와 평균 연령 구하기 (아이디부분 8로 통일된 예제)
select substr(email, 10) "도메인",
count(distinct customer_id) "고객 수",
avg(age) "평균 연령"
from customers
group by 1
** 10인 이유 @ 없는 메일주소도 있음 도메인별로 묶이려면 @ 제외한 10번째자리 부터
** count(distinct 해도 되고), count(customer_id) 컬럼 그대로 써도 됨.
ex) [지역(시도)] 음식점이름 (음식종류)’ 컬럼을 만들고, 총 주문건수 구하기
SELECT concat('[',substr(addr,1,2),']', restaurant_name, ' (',cuisine_type,')')"바뀐 이름",
count(1) "주문건수"
from food_orders
group by 1
** 총 주문''건수"는 음식점별 주문건수이므로 sum이 아닌 count(1).
5. 조건에 따라 다른 방법을 적용하고 싶을 때
if(조건, 조건을 충족할 때, 조건을 충족하지 못할 때)
ex) 음식 타입을 ‘Korean’ 일 때는 ‘한식’, ‘Korean’ 이 아닌 경우에는 ‘기타’ 라고 지정
select restaurant_name,
cuisine_type '원래음식타입',
if(cuisine_type='Korean', '한식', '기타') '음식타입'
FROM food_orders
**오타조심! cuisine
ex) Replace 예시에서 ‘문곡리’ 가 평택에만 해당될 때, 평택 ‘문곡리’ 만 ‘문가리’ 로 수정
select addr as "원래 주소",
if(addr like '%평택%',replace(addr,'문곡리','문가리'), addr)as "바뀐주소"
FROM food_orders
where addr like '%문곡리'
**정답에선 addr 대신 '문가리' (참고)

ex) ★ ★ ★ Group by 2번째 예시에서 잘못된 이메일 주소 (gmail) 만 수정을 해서 사용 ★ ★ ★
select substr(if(email like '%gmail%', replace(email, 'gmail', '@gmail'), email), 10) "도메인",
count(customer_id) "고객수",
avg(age) "평균연령"
from customers
group by 1
** 어려웠다 substr 안에 if 를 넣을 줄은...!!!
잘못된 이메일 주소만 수정할 땐, if(email like '%gmail%', replace ('gmail, '@gmail', email (그 외 그냥 email) //
그리고 substr(범위 (if 절 조건 넣을 수 있음, 그 조건으로 바꾼 범위), 10) - 10번째 이하부터 끝까지 추출★★
6. 조건을 여러가지 지정하고 싶을 때
Case (when~then, else, end)
ex) 음식 타입을 ‘Korean’ 일 때는 ‘한식’, ‘Japanese’ 혹은 ‘Chienese’ 일 때는 ‘아시아’, 그 외에는 ‘기타’ 라고 지정
select restaurant_name,
cuisine_type as "원래 음식타입",
case when cuisine_type='Korean' then '한식'
when cuisine_type='Japanese' then '일식'
when cuisine_type='Chinese' then '중식'
else '기타'
end as "음식 타입"
ex) 음식 단가를 주문 수량이 1일 때는 음식 가격, 주문 수량이 2개 이상일 때는 음식가격/주문수량 으로 지정
select order_id,
price,
quantity,
case when quantity=1 then price
when quantity>=2 then price/quantity
end '음식단가'
from food_orders
*위와 같은 식은 if 로도 쓸 수 있죠! 한 번 연습해보시는 것을 추천합니다!
select order_id,
price,
quantity,
if(quantity>=2, price/quantity, price) '음식단가'
from food_orders
ex) 주소의 시도를 ‘경기도’ 일때는 ‘경기도’, ‘특별시’ 혹은 ‘광역시’ 일 때는 붙여서, 아닐 때는 앞의 두 글자만 사용
select restaurant_name,
addr '원래주소',
case when addr like '경기도%' then '경기도'
when addr like '%특별시%' or addr like '%광역시%' then substr(addr,1,5)
else substr(addr,1,2)
end '시도'
from food_orders
** 경기도 는 단순하니까 Substr 할 필요 없이 그냥 '경기도'로 별명// '특별시' 혹은 '광역시' 는 요청결과가 동일하므로 case when 안에서 or로 묶어서 간단하게! 여기서는 시도가 다르므로 subsr 로 5섯글자까지 추출!
< 조건을 사용할 수 있는 경우 >
1) 새로운 카테고리 만들기 (ex. 음식타입, 고객분류 등)
2) 연산식 적용할 조건 지정하기 (ex. 현금일 때 수수료율, 카드일 때 수수료율 혹은 계산방식 다르게 적용시)
3) 다른 문법 안에서 적용하기 (- if, case 문 안에 다른 문법이나 연산 적용가능
(ex. concat문으로 여러 컬럼 합칠 때, rating 있는 경우 rating을 넣어주고 없는 경우 아무것도 넣지 않도록 concat문 안에 if문 넣을 수 있음)
7. User Segmentation
ex) ★ ★ ★10세 이상, 30세 미만의 고객의 나이와 성별로 그룹 나누기 (이름도 같이 출력) ★ ★ ★
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
** 나이와 성별로 그룹 나누라고 하는데 when 안에 '괄호'로 조건1 (나이범위) 묶어주고 and로 조건2 추가 then !!
** 그 외 나이들은 NULL 이 나와서 요거 어떡하지 ? 했는데,, where 로 딱 그 범위만 지정해줄 수 있음!!
ex) ★ ★ ★ 음식 단가, 음식 종류 별로 음식점 그룹 나누기 ★ ★ ★
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
** 단가를 price/quantity 로 기재! 아시아식 할 때 in 으로 묶은 것. 그외를 역발상으로 not in 으로 앞에꺼 다 묶어서 이게 아닌 것들 '기타' 로 보내버림. segmentation 은 case로 2개 이상 조건 묶어서 한번에 나누기!

<조건문으로 서로 다른 식 적용한 수수료 구해보기>
- 지역과 배달시간을 기반으로 배달수수료 구하기 (식당 이름, 주문 번호 함께 출력)
- (지역 : 서울, 기타 - 서울일 때는 수수료 계산 * 1.1, 기타일 때는 곱하는 값 없음 시간 : 25분, 30분 - 25분 초과하면 음식 가격의 5%, 30분 초과하면 음식 가격의 10%)★ ★ ★
select restaurant_name,
order_id,
delivery_time,
price,
addr,
case when delivery_time>25 and delivery_time<=30 then price * 0.05 * (if(addr like'%서울%', 1.1, 1))
when delivery_time>30 then price * 1.1 * (if(addr like'%서울%', 1.1, 1))
else 0 end '수수료'
from food_orders
** 식을 세울 때, 앞에 있다고 먼저 쓰는게 아니라, 효율적으로 식 세우는 연습! // 곱하는 값이 없는 것도 있는 '서울' 조건은 if 르로 추후에 조건에 따라 곱하기로 뒤에 붙히고// 25분 초과일 때, 30분 초과일 때 조건이 다르므로 이 식으로 case when은 나눔!!// 마지막으로 NULL 안 나오게 그 밖에 수수료는 else 0 적어주기!
- 주문 시기와 음식 수를 기반으로 배달할증료 구하기
- (주문 시기 : 평일 기본료 = 3000 / 주말 기본료 = 3500 음식 수 : 3개 이하이면 할증 없음 / 3개 초과이면 기본료 * 1.2)
** CASE 문으로 혼자
SELECT order_id,
price,
quantity,
day_of_the_week,
case when day_of_the_week = 'weekday' then 3000*if(quantity>3,1.2,1)
when day_of_the_week = 'weekend' then 3500*if(quantity>3,1.2,1)
end '배달할증료'
FROM food_orders
** IF문 으로 (정답)
SELECT order_id,
price,
quantity,
day_of_the_week,
if(day_of_the_week='weekday',3000,3500)*(if(quantity>3,1.2,1)) '배달할증료'
FROM food_orders
** 조건이 주중 아니면 주말이므로 IF 문 가능!! 곱하기 뒤 IF문 또 가능// 조건이 YES of NO 일 때 IF문 으로 좀더 간단하게 게!!

8. 오류해결
문자/숫자 계산을 했더니 오류 -> avg, substring 등 함수를 썼더니 에러메세지에 ‘data type’ 단어가 뜨면서 실행되지 않아요
-> 우리가 실습하는 Mysql 과 다르게, 다른 SQL 문법에서는 data type 이 다를 때 연산이 되지 않을 수 있음.
예를 들면, rating 은 숫자가 포함되어 있지만 문자 형으로 저장이 되어있음.
(출력 결과 컬럼명 옆의 ‘123’ 는 숫자 ‘ABC’ 는 문자로 저장이 되어있다는 의미.)
따라서 문자, 숫자를 혼합하여 함수에 사용 할 때에는 데이터 타입을 변경
--숫자로 변경
cast(if(rating='Not given', '1', rating) as decimal)
--문자로 변경
concat(restaurant_name, '-', cast(order_id as char))
[과제]
다음의 조건으로 배달시간이 늦었는지 판단하는 값을 만들어주세요. - 주중 : 25분 이상 - 주말 : 30분 이상
select order_id,
restaurant_name,
day_of_the_week,
delivery_time,
case when day_of_the_week='weekday' and delivery_time>=25 then 'Late'
when day_of_the_week='weekend' and delivery_time>=30 then 'Late'
else "On_time"
end '지연여부'
from food_orders
** restaurante 이름추가 // 지연되지 않은 값은 else 'On_time'으로 지정//
'Data Analyst > daily' 카테고리의 다른 글
[데이터분석 4일차] (라이브세션 과제: where구문, subquery) (1) | 2024.10.04 |
---|---|
[데이터 분석 3일차 ② ]데이터가 없거나 상식적이지 않을 때 NULL, COALESCE, Pivot Table, Window function (rank, sum, date(포맷함수) (0) | 2024.10.02 |
[데이터 분석 3일차 ①] Subquery, JOIN (1) | 2024.10.02 |
[데이터분석 2일차 ①] (연산, 평균, 갯수, 최대, 최소, Group by, Order by) (1) | 2024.10.01 |
[데이터분석 1일차] (select from/ where) (7) | 2024.09.30 |