작성
·
43
0
select
*,
lead(visit_month, 1) over(partition by user_id order by visit_month) as next_visit_month,
lead(visit_month, 2) over(partition by user_id order by visit_month) as two_next_visit_month
from `advanced.analytics_function_01
select
*,
lead(visit_month, 1) over(partition by user_id order by visit_month) as next_visit_month,
lead(visit_month, 2) over(partition by user_id order by visit_month) as two_next_visit_month,
lag(visit_month, 1) over(partition by user_id order by visit_month) as before_visit_month
from `advanced.analytics_function_01`
/*
전체 계산 할 때 왜 over()를 써야 하는지 몰랐습니다.
그러나 일반 집계 함수의 방식과 비교해보니, 사용 이유를 알게 됐습니다.
집계함수를 사용할 때 over()를 사용했다는 건 '윈도우 함수가 적용된 결과값(각 행마다 결과 값이 반환 되는 것)으로 보겠다'는 의미인 걸 알게 됐습니다.
같은 집계함수를 사용하더라도 '어떤 방식(결과를 1개 행으로만 받아볼지, 여러개 값으로 받아볼지)으로 결과 값을 받아 볼 지' 생각해 봐야 한다는 걸 알았습니다.
*/
select
*,
sum(amount) over() as amount_total
from `advanced.orders`
/*
처음에는 누적합을 구하는 건데 왜 over() 안에 order by를 써야하는지 이해하지 못했습니다.
그러나 누적합도 "어떤 방식으로 계산할지 '계산 방식'"을 지정해 줘야 한다는 걸 알게 됐습니다.
/*
select
*,
sum(amount) over(order by order_id) as cumulative_sum
from `advanced.orders`
select
*,
sum(amount) over(partition by user_id order by order_id) as cumulative_sum_by_user
from `advanced.orders`
/*
over() 안에 사용하는 order by와 over() 밖에서 사용하는 order by를 명확히 이해했습니다.
윈도우 함수에서 사용하는 order by는 '계산 순서'를 정하는 것이고, 윈도우 함수 밖에서 사용한 order by는 '눈에 보이는 정렬'을 컨트롤 한다는 걸 이해했습니다.
이해할 때 '쿼리 작동 순서'를 생각했더니, 큰 도움이 됐습니다.
*/
select
*,
avg(amount) over(order by order_id rows between 5 preceding and 1 preceding) as last_5_orders_avg_amount
from `advanced.orders`
order by
order_id
select
*,
count(user) over(partition by user) as total_query_cnt
from `advanced.query_logs`
order by
query_date
/*
- date 형식 데이터를 extract()로 주 형식으로 바꾸는 걸 알게 됐습니다
- partition by 내에 2개 이상 컬럼을 넣어도 된다는 걸 알게 됐습니다.
*/
with user_query_cnt as (
select
extract(week from query_date) as week_number,
team,
user,
count(user) as query_cnt
from `advanced.query_logs`
group by all
)
select
*,
rank() over(partition by week_number, team order by query_cnt desc) as team_rank
from user_query_cnt
qualify team_rank = 1
order by
1,2
/*
- lag()와 함께 쓰는 over() 사용법이 헷갈렸는데, 실행 후 수정하는 방향으로 쿼리를 작성해 보라고 하신 점이 인상 깊게 와닿았습니다.
*/
with base as (
select
user,
team,
extract(week FROM query_date) as week_number,
count(user) as query_count
from advanced.query_logs
group by all
)
select
*,
lag(query_count, 1) over(partition by user order by week_number) as pre_query_cnt
from base
/*
qualify cumulative_query_cnt != cumulative_query_cnt2
위 쿼리로 정합성을 체크하는 방식을 배우게 됐습니다.
*/
## 4번
with query_cnt as (
select
*,
count(user) as query_count
from advanced.query_logs
group by all
)
select
*,
sum(query_count) over(partition by user order by query_date) as cumulative_query_cnt,
sum(query_count) over(partition by user order by query_date rows between unbounded preceding and current row) as cumulative_query_cnt2
from query_cnt
-- qualify cumulative_query_cnt != cumulative_query_cnt2
/*
- 4번에서 배운 정합성 체크하는 쿼리를 이용해서 컬럼 내 값이 있는지 테스트 해봤습니다.
*/
## 정합성 테스트
-- select
-- *
-- from (
-- select
-- *,
-- last_value(number_of_orders) over(order by date) as last_values_order
-- from raw_data
-- ) as test1
-- where
-- number_of_orders != last_values_order
select
*,
last_value(number_of_orders ignore nulls) over(order by date) as last_values_order
from raw_data
/*
처음에는 1. 평균을 구하고 2. 해당 테이블을 서브쿼리로 두고, lag(컬럼, 2)를 해야 하는줄 알았습니다.
그러나 Frame 사용 방법이 생각났고, 조건에 맞게 범위를 설정해서 문제를 해결했습니다.
*/
## 6번
, base2 as (
select
*,
last_value(number_of_orders ignore nulls) over(order by date) as last_values_order,
from raw_data
)
select
*,
avg(last_values_order) over(order by date rows between 2 preceding and current row) as moving_avg
from base2
/*
- 타임스탬프 데이터를 다루는 다양한 방법을 알게 됐습니다.
- 실무에서는 세션 기준과 보고 싶은 유저 혹은 이벤트를 지정해서 사용해도 된다는 걸 알게 됐습니다.
*/
with base as (
select
event_date,
event_timestamp,
datetime(timestamp_micros(event_timestamp), 'Asia/Seoul') as event_datetime,
event_name,
user_id,
user_pseudo_id
from `advanced.app_logs`
where
event_date = '2022-08-18'
and user_pseudo_id = '1997494153.8491999091'
)
select
*,
sum(session_start) over(order by event_datetime) as session_id
from (
select
*,
case
when second_diff >= 20 then 1
when second_diff is null then 1
else 0
end session_start
from (
select
*,
timestamp_diff(event_datetime, before_event_datetime, second) as second_diff
from (
select
*,
lag(event_datetime, 1) over(partition by user_pseudo_id order by event_datetime) as before_event_datetime
from base
) as base2
) as base3
) as base4
답변 1
0
안녕하세요, 인프런 AI 인턴입니다. 레스님.
윈도우 함수와 null을 다루는 방법에 대한 질문에 감사를 드립니다. 윈도우 함수는 데이터를 다양한 방식으로 분석하는데 강력한 도구이며, null 처리는 데이터 정확성을 유지하는 데 중요한 역할을 합니다.
이 질문을 통해 알아봐야 할 몇 가지 핵심 개념과 일반적인 사용 방법을 설명하겠습니다.
윈도우 함수의 사용 이유:
OVER()
구문은 데이터의 특정 파티션에서 일련의 행에 대한 계산을 수행할 때 사용됩니다. 이러한 함수는 기본적인 집계 함수와는 다르게 각 행에 대해 반복적으로 계산을 수행하여 결과를 제공합니다. 예를 들어, SUM()
함수로 특정 컬럼의 총합을 구할 때 OVER()
를 사용하면 각 행에 대해 누적 합계를 계산할 수 있습니다.NULL 값 처리:
NULL
값은 부재를 의미하므로 집계 작업에서 특별한 고려가 필요합니다. 예를 들어 LAST_VALUE()
함수 사용 시 IGNORE NULLS
옵션을 통해 NULL
값을 무시하고 계산할 수 있습니다.윈도우 함수와 프레임:
ROWS BETWEEN 5 PRECEDING AND 1 PRECEDING
지정은 현재 행 전의 5개 행부터 1개 행까지 고려하여 계산을 수행하겠다는 의미입니다.질문에 대한 유사한 기존 답변을 확인하고 싶다면, 아래 링크들을 참고해 보시면 좋겠습니다.
윈도우 함수. OVER(), PARTITION BY와 ORDER BY차이 알고 싶습니다!
OVER()
, PARTITION BY
와 ORDER BY
의 차이점에 대한 설명이 포함되어 있어 도움이 될 수 있습니다.SQL에서 윈도우 함수와 null 처리 문제 - 해결 사례
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.