인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

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

김하제님의 프로필 이미지

작성한 질문수

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

[빠짝스터디 2주차 과제] 윈도우 함수 연습 문제

작성

·

99

·

수정됨

0

강의 문제 1) user들의 다음 접속월과 다다음 접속월을 구하는 쿼리를 작성해주세요.

-- 출제의도: 윈도우 함수(LEAD)를 사용하여 파티션을 나눠 데이터를 탐색할 수 있는가? 
SELECT 
  user_id
  , visit_month AS visit_month_m0
  , LEAD(visit_month) OVER (PARTITION BY user_id ORDER BY visit_month) AS visit_month_m1
  , LEAD(visit_month, 2) OVER (PARTITION BY user_id ORDER BY visit_month) AS visit_month_m2
FROM advanced.analytics_function_01
ORDER BY user_id;

강의 문제 2) user들의 다음 접속월과 다다음 접속월, 이전 접속월을 구하는 쿼리를 작성해주세요

-- 출제의도: 윈도우 함수(LEAD)와 (LAG)을 함께 사용하여 파티션을 나눠 데이터를 탐색할 수 있는가? 
SELECT 
  user_id
  , visit_month AS visit_month_m0
  , LEAD(visit_month) OVER (PARTITION BY user_id ORDER BY visit_month) AS visit_month_m1
  , LEAD(visit_month, 2) OVER (PARTITION BY user_id ORDER BY visit_month) AS visit_month_m2
  , LAG(visit_month) OVER (PARTITION BY user_id ORDER BY visit_month) AS visit_month_p1
FROM advanced.analytics_function_01
ORDER BY user_id;

강의 문제 3) Frame 설정을 활용한 윈도우 함수 사용

SELECT 
  order_id
  , order_date
  , user_id
  , amount
  , SUM(amount) OVER (ORDER BY order_date, order_id ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS amount_total
  , SUM(amount) OVER (ORDER BY order_date, order_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_sum
  , SUM(amount) OVER (PARTITION BY user_id ORDER BY order_date, order_id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_sum_by_user
  , AVG(amount) OVER (ORDER BY order_date, order_id ROWS BETWEEN 5 PRECEDING AND 1 PRECEDING) AS last_5_orders_avg_amount
FROM advanced.orders
--QUALIFY last_5_orders_avg_amount >= 150
ORDER BY order_id;

윈도우 함수 연습문제 1) 사용자별 쿼리를 실행한 총 횟수를 구하는 쿼리를 작성해주세요. 단, GROUP BY를 사용해서 집계하는 것이 아닌, query_logs의 데이터 우측에 새로운 컬럼을 만들어주세요.

-- 출제의도: 윈도우 함수의 집계 함수 중 COUNT를 사용할 수 있는가? 
SELECT
  *
  , COUNT(user) OVER (PARTITION BY user) AS total_query_cnt
FROM advanced.query_logs
ORDER BY query_date, user;

윈도우 함수 연습문제 2) 주차별로 팀 내에서 쿼리를 많이 실행한 수를 구한 후, 실행한 수를 활용해 랭킹을 구해주세요. 단, 랭킹이 1등인 사람만 결과가 보이도록 해주세요.

-- 출제의도: GROUP BY와 윈도우 함수(순위)를 함께 사용할 수 있는가?
SELECT 
  *
  , RANK() OVER (PARTITION BY week_number, team ORDER BY query_cnt DESC) AS team_rank
FROM 
  (SELECT 
    EXTRACT(WEEK FROM query_date) AS week_number
    , team
    , user
    , COUNT(user) AS query_cnt
  FROM advanced.query_logs
  GROUP BY ALL)
QUALIFY team_rank = 1
ORDER BY week_number, team;

윈도우 함수 연습문제 3) (2번 문제에서 사용한 주차별 쿼리 사용) 쿼리를 실행한 시점 기준, 1주 전에 쿼리 실행 수를 별도의 컬럼으로 확인할 수 있는 쿼리를 작성해주세요.

-- 출제의도: GROUP BY와 윈도우 함수(LAG)를 함께 사용할 수 있는가?
SELECT 
  *
  , LAG(query_cnt) OVER (PARTITION BY user ORDER BY week_number) AS prev_week_query_count 
FROM 
  (SELECT 
    user
    , team
    , EXTRACT(WEEK FROM query_date) AS week_number
    , COUNT(user) AS query_cnt
  FROM advanced.query_logs
  GROUP BY ALL)
  ORDER BY user, week_number;

윈도우 함수 연습문제 4) 시간 흐름에 따라, 일자별로 유저가 실행한 누적 쿼리 수를 작성해주세요.

-- *FRAME의 DEFAULT 값: UNBOUNDED PRECEDING ~ CURRENT ROW
-- 출제의도: GROUP BY와 윈도우 함수(SUM-누계합)를 함께 사용할 수 있는가?
SELECT 
  *
  , SUM(query_cnt) OVER (PARTITION BY user ORDER BY query_date) AS cumulative_query_count
FROM
(SELECT 
  user
  , team
  , query_date
  , COUNT(user) AS query_cnt
FROM advanced.query_logs
GROUP BY ALL)
ORDER BY user, query_date;

윈도우 함수 연습문제 5) 다음 데이터는 주문 횟수를 나타낸 데이터입니다. 만약 주문 횟수가 없으면 NULL로 기록됩니다. 이런 데이터에서 NULL 값이라고 되어있는 부분을 바로 이전 날짜의 값으로 채워주는 쿼리를 작성해주세요.

-- 출제의도: 윈도우 함수(LAST_VALUE)에서 IGNORE NULLS가 필요한 상황을 이해할 수 있는가?
WITH raw_data AS(
 SELECT DATE '2024-05-01' AS date, 15 AS number_of_orders UNION ALL
 SELECT DATE '2024-05-02', 13 UNION ALL
 SELECT DATE '2024-05-03', NULL UNION ALL
 SELECT DATE '2024-05-04', 16 UNION ALL
 SELECT DATE '2024-05-05', NULL UNION ALL
 SELECT DATE '2024-05-06', 18 UNION ALL
 SELECT DATE '2024-05-07', 20 UNION ALL
 SELECT DATE '2024-05-08', NULL UNION ALL
 SELECT DATE '2024-05-09', 13 UNION ALL
 SELECT DATE '2024-05-10', 14 UNION ALL
 SELECT DATE '2024-05-11', NULL UNION ALL
 SELECT DATE '2024-05-12', NULL
)

-- SELECT
--   date
--   , IFNULL(number_of_orders, LAG(number_of_orders) OVER (ORDER BY date)) AS number_of_orders
-- FROM raw_data
-- ORDER BY date;

SELECT 
  *
  , LAST_VALUE(number_of_orders IGNORE NULLS) OVER (ORDER BY date) AS number_of_orders
FROM raw_data
ORDER BY date;

윈도우 함수 연습문제 6) 5번 문제에서 NULL을 채운 후, 2일 전 ~ 현재 데이터의 평균을 구하는 쿼리를 작성해주세요.

-- 출제의도: 예외 값을 처리한 이후, 윈도우 함수로 이동 평균을 계산할 수 있는가?
WITH raw_data AS(
 SELECT DATE '2024-05-01' AS date, 15 AS number_of_orders UNION ALL
 SELECT DATE '2024-05-02', 13 UNION ALL
 SELECT DATE '2024-05-03', NULL UNION ALL
 SELECT DATE '2024-05-04', 16 UNION ALL
 SELECT DATE '2024-05-05', NULL UNION ALL
 SELECT DATE '2024-05-06', 18 UNION ALL
 SELECT DATE '2024-05-07', 20 UNION ALL
 SELECT DATE '2024-05-08', NULL UNION ALL
 SELECT DATE '2024-05-09', 13 UNION ALL
 SELECT DATE '2024-05-10', 14 UNION ALL
 SELECT DATE '2024-05-11', NULL UNION ALL
 SELECT DATE '2024-05-12', NULL
)

SELECT 
  *
  , ROUND(AVG(number_of_orders) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) 
      , 1) AS moving_avg
FROM(
  SELECT
    date
    , IFNULL(number_of_orders, LAG(number_of_orders) OVER (ORDER BY date)) AS number_of_orders
  FROM raw_data)
ORDER BY date;

윈도우 함수 연습문제 7) app_logs 테이블에서 Custom Session을 만들어주세요. 이전 이벤트 로그와 20초가 지나면 새로운 Session을 만들어 주세요.

-- *Session은 숫자로(1,2,3…) 표시해도 됩니다. 
-- **2022-08-18일의 user_pseudo_id(1997494153. 8491999091)은 session_id가 4까지 나옵니다
-- 출제의도: 윈도우 함수를 웹 로그 데이터에 적용하여 활용할 수 있는가?

-- Step 1. Session 정보 추출 
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
    , DATETIME(TIMESTAMP_MICROS(LAG(event_timestamp) OVER (PARTITION BY user_pseudo_id ORDER BY event_timestamp)), 'Asia/Seoul') AS before_event_datetime
  FROM advanced.app_logs
  WHERE event_date = '2022-08-18'
    AND user_pseudo_id = '1997494153.8491999091'
),

-- Step 2. 세션 유지 시간 및 신규 세션 여부 계산
session_info AS(
  SELECT 
    *
    , TIMESTAMP_DIFF(event_datetime, before_event_datetime, SECOND) AS second_diff
    , CASE 
        WHEN TIMESTAMP_DIFF(event_datetime, before_event_datetime, SECOND) >= 20 
          OR TIMESTAMP_DIFF(event_datetime, before_event_datetime, SECOND) IS NULL THEN 1 
        ELSE NULL 
      END AS session_start
  FROM base
)

-- Step 3. 신규 세션 id 세팅
SELECT 
  *
  , SUM(session_start) OVER (PARTITION BY user_pseudo_id ORDER BY event_datetime) AS session_id
FROM session_info
ORDER BY event_date, event_timestamp;

 

답변 1

0

인프런 AI 인턴님의 프로필 이미지

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

윈도우 함수, 특히 LEAD와 LAG 함수의 활용법에 대해 질문해주셨군요. 이를 통해 데이터 분석에서 시계열 데이터를 탐색하고 원하는 결과를 도출하는데 매우 유용함을 알 수 있습니다. 김하제님께서 작성하신 SQL 쿼리는 다음 접속월, 다다음 접속월 및 이전 접속월을 구하는 방법을 잘 보여주고 있습니다. 이러한 윈도우 함수는 특정 파티션 내에서 데이터를 순서대로 정렬하고 탐색할 수 있게 도와줍니다.

관련하여 도움이 될만한 유사한 질문과 답변 링크들을 소개합니다:

이 유사한 질문들을 통해 각 윈도우 함수의 성능이나 가능한 실수들을 이해하며 개선할 수 있는 기회가 되실 것입니다. 궁금하신 점이 있으면 언제든지 추가로 질문해 주세요!

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