인프런 커뮤니티 질문&답변

김승규님의 프로필 이미지
김승규

작성한 질문수

BigQuery(SQL) 활용편(퍼널 분석, 리텐션 분석)

[인프런 빅쿼리 빠짝스터디 2주차] 윈도우 함수, FRAME 설정, QUALIFY

작성

·

33

0

<윈도우 함수>

연습문제 1

SELECT
  user_id,
  visit_month,
  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
ORDER BY user_id

연습문제 2

SELECT
  user_id,
  visit_month,
  LAG(visit_month, 1) OVER(PARTITION BY user_id ORDER BY visit_month) as prev_visit_month,
  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
ORDER BY user_id

추가문제 - 유저의 첫번째 방문월과 마지막 방문월 구하기

SELECT
  user_id,
  visit_month,
  FIRST_VALUE(visit_month) OVER(PARTITION BY user_id ORDER BY visit_month) as first_visit_month,
  LAST_VALUE(visit_month) OVER(PARTITION BY user_id ORDER BY visit_month) as last_visit_month,
FROM advanced.analytics_function_01
ORDER BY user_id

<FRAME 설정>

advanced.order 문제

SELECT
  *,
  SUM(amount) OVER() as amount_total,
  SUM(amount) OVER(ORDER BY order_id) as cumulative_sum,
  SUM(amount) OVER(PARTITION BY user_id ORDER BY order_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) as cumulative_sum_by_user,
  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, user_id

<연습문제>

연습문제 1

SELECT
  *,
  COUNT(*) OVER(PARTITION BY user) as total_query_cnt
FROM advanced.query_logs
ORDER BY user

연습문제 2

WITH base 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 base
QUALIFY team_rank=1
ORDER BY week_number

연습문제 3

WITH base as (
  SELECT
    user,
    team,
    EXTRACT(WEEK FROM query_date) as week_number,
    COUNT(user) as query_cnt,
  FROM advanced.query_logs
  GROUP BY ALL
)
SELECT 
  *,
  LAG(query_cnt, 1) OVER(PARTITION BY user ORDER BY week_number) as prev_week_query_count
FROM base

연습문제 4

WITH base as (
  SELECT
    user,
    team,
    query_date,
    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_count
FROM base
ORDER BY user

연습문제 5

-- SELECT
--   *,
--   IF(number_of_orders is NULL, prev_number_of_orders, number_of_orders) as result_number_of_orders,
-- FROM (
--   SELECT
--     *,
--     LAG(number_of_orders, 1) OVER(ORDER BY date) as prev_number_of_orders
--   FROM raw_data
-- )
-- 이 방법은 전의 값들이 Null이 여러개면 제대로 안나옴...!

SELECT
  *,
  IF(number_of_orders is NULL, last_number_of_orders, number_of_orders) as result_number_of_orders,
FROM (
  SELECT
    *,
    LAST_VALUE(number_of_orders IGNORE NULLS) OVER(ORDER BY date) as last_number_of_orders
  FROM raw_data
)

연습문제 6

SELECT
  *,
  AVG(result_number_of_orders) OVER(ORDER BY date ROWS BETWEEN 2 PRECEDING and CURRENT ROW) as moving_avg
FROM (
  SELECT
    *,
    IF(number_of_orders is NULL, last_number_of_orders, number_of_orders) as result_number_of_orders,
  FROM (
    SELECT
      *,
      LAST_VALUE(number_of_orders IGNORE NULLS) OVER(ORDER BY date) as last_number_of_orders
    FROM raw_data
  )
)

연습문제 7

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'
),

base2 as (
  SELECT
    *,
    LAG(event_datetime, 1) OVER(PARTITION BY user_pseudo_id ORDER BY event_datetime) as before_event_datetime
  FROM base
)

SELECT
  *,
  SUM(session_start) OVER(PARTITION BY user_pseudo_id ORDER BY event_timestamp) as session_id
FROM (
  SELECT
    *,
    IF(second_diff is NULL or second_diff > 20, 1, NULL) as session_start
  FROM (
    SELECT
      *,
      DATETIME_DIFF(event_datetime, before_event_datetime, second) as second_diff
    FROM base2
  )
)
ORDER BY event_timestamp

배운점&느낀점

  1. EXTRACT(WEEK FROM query_date) as week_number : date 정보에서 week 정보 등을 추출할 수 있는 함수

  2. DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') as event_datetime : timestamp 형태의 데이터를 날짜로 바꿀 수 있는 함수

  3. LAST_VALUE(number_of_orders IGNORE NULLS)... 그냥 마지막 값은 LAST_VALUE, 이전 데이터 중 null값이 아닌 마지막 값을 가져오고 싶을 때는 IGNORE NULLS를 사용해야 함. (5번 연습문제에서 처음에는 LAG 함수를 사용해서 null이 여러 개 연속인 경우가 있어 제대로 값을 가져오지 못했고, LAST_VALUE 윈도우 함수에서IGNORE NULLS 를 까먹어서 null 처리가 또 안됐었다.)

  4. With절과 서브쿼리 절을 어떤 상황에 사용할지 아직 잘 모르겠다.

  5. CASE WHEN절 사용법이 익숙치 않았다. (문제를 풀 때 IF절을 사용했던 부분에서 강의에서는 CASE WHEN을 사용)

  6. 윈도우 함수를 제대로 처음 배워봤는데, 어려웠지만 유용한 부분이 많아 사용할 일이 많을 것 같다.

     

답변 1

0

안녕하세요, 인프런 AI 인턴입니다. 김승규님.

윈도우 함수 및 다양한 BigQuery 기능에 대한 실습을 진행하신 것에 대해 공유해 주셔서 감사합니다. 윈도우 함수는 SQL에서 굉장히 유용한 기능으로, 데이터의 복잡한 분석에 특히 유리합니다. 각종 함수와 메소드를 통해 데이터를 더욱 의미 있게 해석하고 처리할 수 있습니다.

김승규님의 연습에서처럼 LEAD, LAG, FIRST_VALUE, LAST_VALUE와 같은 함수들을 사용하면, 순서에 따라 데이터의 앞뒤 값들을 손쉽게 비교하거나 참조할 수 있어 데이터 패턴을 파악하는 데 큰 도움이 됩니다. 또한, 데이터를 그룹화하고 특정 기준에 따라 순위를 매기거나 집계하는 데 윈도우 함수는 매우 유용합니다.

관련 질문 URL

아래의 링크에서는 윈도우 함수와 관련된 다양한 예제와 논의를 확인하실 수 있습니다:

  1. BigQuery에서 윈도우 함수 활용하기

    • 이 질문에서는 기본적인 윈도우 함수 활용법과 이를 이용한 복잡한 데이터 분석에 대한 논의가 이루어졌습니다.
  2. SQL 윈도우 함수의 다양한 예제

    • 여러 가지 윈도우 함수의 사용 예제를 통해 개념을 더 깊이 이해하게 될 것입니다.
  3. 쿼리 최적화 방법과 윈도우 함수 사용시 주의사항

    • 윈도우 함수 사용 시 성능 이슈와 관련된 문제점 및 이를 해결하기 위한 방법에 대한 정보를 얻을 수 있을 것입니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

김승규님의 프로필 이미지
김승규

작성한 질문수

질문하기