25.5.2TIL

황효정·2025년 5월 2일

데이터 분석

목록 보기
54/88
post-thumbnail

QCC 5회차.
오늘의 qcc는 최악이었다. 한동안 머신러닝이랑 개인과제, 또다시 새롭게 시작된 태블로 강의 듣느라 sql을 아예 못하고 있었다. 그리고 이게 이제 결과로 나타나는거지하하

아까 qcc 하구 나서 나는 아예 갈피를 못잡겠었는데 다른분들은 그래도 갈피를 잡으셨구나,, 다 틀린것에 대해서 멘탈이 나갔었는데, 산책하면서 멘탈을 다시 다잡았다. 그래도 다행인것은 이번 풀이세션에서는 뭔가 어떤식으로 풀어야하는지 조금 갈피가 잡혔달까.. (원래는 들어도 뭔소린가-..,.할머니눈 했었음)

그래서 작성해보는 qcc오답노트 - 오답 원인 분석, 왜 틀렸는지, 정답은 어떤 구조로 흘러가는지 정리하기.

1번문제

여기서 조건을 살펴보면 category값이 'n/a' 또는 null로 되어 있는 경우-라는 조건이 있다.
이 조건에서 나는 'n/a' 조건을 어떻게 해야할지 알지 못했다. 그냥 is null로 퉁쳤음.->보니까 이게 조건이 아예 'n/a'로 되어있는 조건도 있고 null처리도 되어있는 조건이 있는 듯하다. 저 엔에이라는게 아예 문자로 되어있는 것 같음. 그래서 저거랑 null처리 ..

암튼 그래서 처음에는 is null이라는 조건을 주었는데, 이게 처음에는 작동이 되지 않았다. 아무런 값도 나오지 않음. 그래서 당황함. 아니,, is null이 아니면 어떻게 해야함? : 나중에 알고보니 아예 빈 값은 ''이렇게 표현해주면 되는 것이었음. ->나중에는 튜터님이 빈값에다가 null값을 처리해주셔서 is null했을 때 값이 나왔었다.

❓이걸 실무에서는 어떻게 알아볼 수 있을까?->제대로 된 값이 없을 경우에 null처리되어있는지, 아예 비어있는건지 아니면 오늘 이 조건처럼 'n/a'값 처리가 되어있는지 먼저 알아보아야겠다.

암튼 넘어가서 이거는 그냥 is null을 해주면 됨. 정답쿼리는 이따가 튜터님이 올려주시면 그거랑 또 비교해보자.
밑에 있는 코드가 내가 처음 제출한 코드이다. 뭔가 with 구문을 사용해서 해줘야 할 것 같은데 그다음에 어떻게 써야할지 모르겠어서 여기서 그만 두었다. 아 1:1코치좀 부탁드려요ㅕ,,,하,, 일단 해보자.

-- 2024.4.15이전 상담만 대상으로 뽑아야 함.->조건 주기
-- category 컬럼에서 없는것에 대한 count 구해야 함.
-- 전체 id 수 % 카테고리 count 하면 됨. 소수점 구하는게 round였던 것 같음.
-- 날짜 들어가 있는 쿼리 어렵게 느껴짐. 이 부분 보충하기
-- 원래 데이트포멧하면 새로운 컬럼이 생기는건가요..?, 왜 조건에 is null을 하면 0행이 반환되는지,,?
-- category count 를 구할 때 조건이 is null을 사용하면 아예 아무런 결과값이 나오지 않아서 ,,, 이거 어떻게 구해야 할까요? 왜 아무것도 나오지 않는건가요?
with null_cnt as (select count(id)
from
(select *, date_format(call_date, '%Y-%m-%d') date_f
from calls) a
where date_f < '2024-04-15' and category is null)

with all_cnt as (select count(id)
from
(select *, date_format(call_date, '%Y-%m-%d') date_f
from calls) a
where date_f < '2024-04-15')

select

일단 틀린것 1번째: 날짜 조건. 저번qcc에서도 한번 그랬는데, 그 조건 중에 몇년몇월몇일까지인 조건이 있다면 그 날짜의 23:59:59까지의 시간까지 포함하는 것인데, 이번에도 이거를 생각을 못했다. 항상 날짜 계산해야되는거 나오면 약간 좀 헷갈린다고 해야하나. 암튼 날짜쿼리 좀 어렵게 느껴진다.. 이거를 date_format을 해서 날짜 형식을 바꿔줘야 하는건지부터 시작해서 계산은 어떻게 하고.. 이런 것들을 잘 모르겠다. 날짜 형식만 집중으로 또 풀어봐야겠다 라는 생각이 든다.

이번에 풀이할 때 날짜 컬럼을 date_format함수를 사용해서 년,월,일로 바꿔버렸다.(사실 오늘 오랜만에 써서 포맷팅방식 까먹음.(%위치,'이 아이를 써야한다는 사실) 다시한번 리마인드: '%Y-%m-%d')
__하지만 그러면 안되었던 것 같다. 왜냐하면 저 시간까지 포함을 했어야 하기 때문에. 신기한게 저 날짜를 그냥 년월일로 바꿔버리고 그것보다 작은 값들이 나와버린다.(왜그러지..?)
확인해보는 쿼리: 오늘 또 배운 것(사실 여러번 말씀해주신 것 같지만 오늘에서야 확인해본다..ㅎㅎ)

💡max값을 확인해보면 실제 값이 잘 뽑혔는지 확인할 수 있다.

select max(call_date)
from calls
where call_date <= '2024-04-15'
# 값
max(call_date)
2024-04-14 22:18:00
1 row returned

보다시피4월 15일까지로 조건을 걸어놓으면- 14일의 가장 늦은 시간이 나오는 것을 확인해볼 수 있다.- 아 근데 진짜 왜그런거지..?
아하-!: 이게 그냥 날짜를 2024-04-15 이렇게 해버리면 뒤의 시간은 저절로 디폴트 값이 00:00:00 이렇게 되는 것 같다. 그래서 항상 그 전날까지로 되는 듯 하다. 그렇다면.. 값을 줄 때

select max(call_date)
from calls
where call_date <= '2024-04-15 23:59:59'

#값
max(call_date)
2024-04-15 22:43:00
1 row returned

4월 15일까지의 값이 포함되어서 나온 것을 확인해볼 수 있다. 아하 이렇게 해야하는거구나. 담부터 이런 조건 나오면 꼭 맞게 해야지! 근데 이게 qcc해보신 분들은 아시겠지만, 괜히 시간 제한 있으니까 그 마음의 여유가 없다. 지금은 오답하는시간이고 시간제한이 없으니 마음이..사실 편하진 않음.. 할 거 수천가지기 때문에 이것도 정확하게 머릿속에 빨리 집어넣고 그다음 진도 나가야됨..흙흙
그,, 대신 이것의 전제조건은- 이 컬럼의 값이 날짜랑 시간이랑 같이 있느냐이다. 이번 문제의 저 call_date컬럼의 값들은 다 날짜+시간이 같이 나와있는 데이터 타입을 가지고 있었다. 암튼 담부턴 이 조건은 안틀린다고-!!!!!!!!이야아아ㅏ아아앙아아ㅏ하

2번째 자 그담으로; 넘어가보면- 이제 구해야 하는 것이 두가지이다. 분모에 올 값, 분자에 올 값. 나는 이 두 값을 도대체 어떻게 구해야 하는지 로직이 돌아가지 않았다.- 그래서 내가 생각해 낸 것이 with 구문이었고. 이거를 어떻게 해야할지가 고민이었다. 그래서 거기서 끝나버림. 근데 해설 세션들으면서 알게된 것은 분자,분모를 모두 select 절에다가 구해줘야 하는 것-을 알게 되었다. 그래서 분모에 올 값은: 조건에 맞는 id의 갯수, 분모에 올 값은 : null값인 아이디의 갯수이다. 이거를 나눠주고 100을 곱해주고 round해서 소숫점 자리까지 구해주면 끝이다.- (말은 쉽지^^이제 해보자)-> 이 둘을 어떻게 같이 select절에서 구해주냐고... 으악!!!! 음.. 일단 내 머리의 한계로는 count 를 구해주는 것밖에는,, 하지만 머리를 더 굴려보면,, 이거를 가장 쉽게 하려는 것...은,,,은,,,,은,,,,은,,,,은,,,

일단 전체 id의 갯수 구하는 식과 출력값:

select count(id)
from calls
where call_date <= '2024-04-15 23:59:59'

#출력값
count(id)
888

그리고 null값인 거랑 n/a값인 것의 id갯수 구하는 식, 출력값:

select count(id)
from calls
where call_date <= '2024-04-15 23:59:59' and 
category is null or category = 'n/a'

#출력값
count(id)
186

근데 여기서 왠지 괄호를 묶어주고 싶어졌다.- 뭔가 분자값이 186이 아닌것 같았고(아까 정답에서), 뭔가 조건이 3개나 되는데 다 and 조건이 아니라 or 조건도 있어서 확실히 구분을 해줘야 할 것 같았다. 그래서 바꿔본 쿼리

select count(id)
from calls
where call_date <= '2024-04-15 23:59:59'and 
(category is null or category = 'n/a')

#출력값
count(id)
177

확실히 달라짐.. 왜 달라진거지,,, 이거 이유를 좀 알고 싶다..9개의 행은 어디로 가버린걸까. 그 9개의 행은 뭐였을까?
💡💡💡💡💡💡‼️뭔지 알겠음!!! 뭐냐면- 처음 조건은 저 식을 해석해보면- 2024년4월15일까지의 call_date날짜와 category의 값이 null값인 행을 찾아왔을 거고, 그 값 '또는' 카테고리가 n/a인 값을 가져왔을 것이다. 그래서- 카테고리가 n/a인 값은 날짜가 어떤 날짜이든 상관없는 모든 행을 포함한다. 그래서 더 많아진 것 같다.

그리고 두번째 조건은 날짜가 2024년4월15일까지'이면서'-카테고리값이 null값이거나 n/a값인 행들을 찾아오는거니까 그 아까 첫번째에서 날짜가 4월 15일 이후의 n/a값들이 빠진거라고 볼 수 있다. 이 값들이 결국은 9개가 있는거라고 생각하면 되겠다.
와우 - 나 자신 대단해 -사실 쳇지피티 켜서 물어보려고까지 하다가 -그어떤 수학전교1등 아이가 한 문제를 풀때까지 끝까지 붙잡고 있다고 했던게 생각이 났다. 그 아이가 말하기를 - 절대 답지를 보지 않는덴다. 왜냐하면 본인이 고민하고 결국은 본인이 풀어내야 머릿속에 남는다고 하였다. 그래서 계속 고민하면서 저 식을 다시 뜯어보았더니 보이대. 하하하ㅏ 아주 기분이 좋구만. 이렇게 하나씩 풀어간다는게 아주 기분이 좋다.

그래서 일단은 값을 따로따로 구하긴 했는데, 이거를 어떻게 한꺼번에 한 쿼리로 구할 수 있을까-를 이제 생각해보아야 한다.

일단은 case when 구문을 사용해서 구해보았다.-아까 정답쿼리보니까 그렇게 구하는 것 같았음..^^

select case when category is null or category = 'n/a' then count(1) end as null_cnt,
  count(1) 
from calls
where call_date <= '2024-04-15 23:59:59'

#출력값
null_cnt	count(1)
NULL	    888

근데 null 값이 나와버림.. 왜 ,, 도대체 왜..?

다시 해봄.

select sum(case when category is null or category = 'n/a' then 1 end) as null_cnt,
  count(1) 
from calls
where call_date <= '2024-04-15 23:59:59'

#출력값
null_cnt	count(1)
177	        888

아니 위에거는 안되는데 밑에거는 왜 되는거야ㅣㅣ..?도대체 why../???
->쳇지피티한테 물어봤을 때: case when 구문은 한 행의 조건을 판단하는 문법이라고 함. 그래서 거기에 해당되는 값을 반환하는건데, 여기서 계산식에다가 집계함수를 넣어버리면 집계함수란- 여러행을 하나로 묶어서 계산하는 것이기 때문에 논리적으로 모순이라고 함.
암튼 그래서 제대로 된 쿼리 가지고 이제 저걸 둘이 나눴다.->

select count(case when category is null or category = 'n/a' then 1 end) as null_cnt,  / count(1) 
from calls
where call_date <= '2024-04-15 23:59:59'

이렇게 했더니 신택스에러가 났다. 도대체 왜???? 싶어서 이번엔 바로 지피티한테 물어보았다-> "여기서 문제는 AS 별칭을 선언하면서 수식을 동시에 써버린 것이에요."

그렇댄다. 저 별칭을 빼줘야 한다.->나 진자 sql 감 어디갔음..?^%^
마지막 계산식까지 해주기:

select round((count(case when category is null or category = 'n/a' then 1 end)  / count(1)) * 100, 1) as uncategorised_call_pct 
from calls
where call_date <= '2024-04-15 23:59:59'

#출력값
uncategorised_call_pct
19.9

이제 튜터님 쿼리 가져와서 비교해보기!

select
  round((sum(if(category = 'n/a' or category is null, 1, 0))/
    count(1)) * 100, 1) as uncategorized_call_pct
from calls
where date_format(call_date, '%Y-%m-%d') < '2024-04-16'

#출력값
uncategorized_call_pct
19.9

답은 맞았다! 근데 살짝 풀이가 다름. 근데 저렇게 case when 써서 하는 것에다가 1로 반환해줘서 sum하거나 count하거나 하는방법 많이 쓰일 것 같다. 잘 기억해둬야겠다. 이런 문제 또 풀어보고 싶음. -암튼 1번 문제 오답완료

한 문제 오답하는 데 시간이 엄청 걸리네?ㅎㅎ^^ 내 이럴줄 알았찌. 오늘 하루죙일 이것만 하고 있겠구만..하... 일단은 sql이 젤 중요하니까 하나하나 정확하게 뜯어보면서 고민해보면서 풀어보자ㅎㅎ

2번문제


2번문제도 어려웠다. 이거를 어떻게 풀지...? 싶은
일단 나의 첫 쿼리는 이렇다.

-- 결과 나이 구간 오름차정렬, 소수점 2자리 반올림 출력
select u.user_id, event_type
from app_events a inner join user_profiles u on a.user_id = u.user_id
where signup_date >= 2023-01-01
group by u.user_id, event_type
order by age_bucket, u.user_id

#출력값
user_id	 event_type
2	     view
2	     order
2	     review
4	     order
4	     view
4	     review
7	     view
7	     review
7	     order
12	     view
10 rows returned

user_id별로 뷰랑 오더가 있는지는 확인을 했는데 그담에 어떻게 해야될지 모르겠어가지고 그냥 이 상태로 제출했었다.

아 근데,,, 이건 담에 해야할 듯,, 다른거부터 해야될 것 같아,,

profile
청지기

0개의 댓글