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

김희은님의 프로필 이미지
김희은

작성한 질문수

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

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

작성

·

19

0


-- 함수(컬럼) OVER (PARTITION BY 파티션 컬럼 ORDER BY 정렬할 컬럼) AS 
-- LEAD, LAG  -> 함수(컬럼,순서). 순서를 명시하지 않으면 디폴트 1

-- 1) 

select 
  *,
  LEAD(visit_month) OVER (PARTITION BY user_id ORDER BY visit_month ASC) AS lead_visit_month,
  LEAD(visit_month,2) OVER (PARTITION BY user_id ORDER BY visit_month ASC) AS lead2_visit_month
FROM advanced.analytics_function_01
ORDER BY user_id
;
-- 여기서 *를 쓰고 진행하는 이유가 있나?

-- 2) 
select 
  *,
  LEAD(visit_month,1) OVER (PARTITION BY user_id ORDER BY visit_month ASC) AS after_visit_month,
  LEAD(visit_month,2) OVER (PARTITION BY user_id ORDER BY visit_month ASC) AS after_visit_month,
  LAG(visit_month,1) OVER (PARTITION BY user_id ORDER BY visit_month ASC) AS before_visit_month
FROM advanced.analytics_function_01
ORDER BY user_id, visit_month
;

-- 3) 

select 
  *,
  LEAD(visit_month,1) OVER (PARTITION BY user_id ORDER BY visit_month ASC) AS after_visit_month,
  LEAD(visit_month,1) OVER (PARTITION BY user_id ORDER BY visit_month ASC) - visit_month
FROM advanced.analytics_function_01
ORDER BY user_id, visit_month
;

-- 서브쿼리
SELECT 
  *,
  after_visit_month-visit_month AS diff
FROM (
  select 
    *,
    LEAD(visit_month,1) OVER (PARTITION BY user_id ORDER BY visit_month ASC) AS after_visit_month
  FROM advanced.analytics_function_01
)
ORDER BY user_id, visit_month
-- 쿼리가 길어지는 것을 무서워하지말고 쿼리를 덜 수정하는 방향으로 하자 

-- # 추가문제 : 이 데이터셋 기준으로 user_id의 첫번째 방문월, 마지막방문월 구하는 쿼리 작성하기 first_value, last_value
SELECT 
  *,
  FIRST_VALUE(visit_month) OVER (PARTITION BY user_id ORDER BY visit_month ASC) AS first_visit_month,
  LAST_VALUE(visit_month) OVER (PARTITION BY user_id ORDER BY visit_month ASC) AS last_visit_month
FROM advanced.analytics_function_01
ORDER BY user_id, visit_month
;

-- 4) 시간의 흐름에 따라, 일자별로 유저가 실행한 누적 쿼리 수를 작성해주세요
SELECT
  *,
  SUM(query_cnt) OVER(PARTITION BY user ORDER BY query_date) AS cumulative_sum,
  SUM(query_cnt) OVER(PARTITION BY user ORDER BY query_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_sum2
FROM (
  SELECT
    query_date,
    team,
    user,
    COUNT(user) AS query_cnt
  FROM advanced.query_logs
  GROUP BY ALL
)
ORDER BY user, query_date

-- 5)
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 UNION ALL
)

SELECT
	*,
	LAST_VALUE(number_of_order IGNORE NULLS) OVER (ORDER BY date) AS last_value_orders
FROM raw_data

-- 6)
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
), filled_data AS (
	SELECT
		* EXCEPT(number_of_orders),
		**LAST_VALUE**(number_of_orders **IGNORE NULLS**) OVER (ORDER BY date) AS number_of_orders
	FROM raw_data
)

SELECT
	*,
	AVG(number_of_orders) OVER (ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg
FROM filled_data



-- 7) app_logs 테이블에서 Custom Session을 만들어 주세요. 이전 이벤트 로그와 20초가 지나면 새로운 Session을 만들어 주세요. Session은 숫자로 (1, 2, 3 …) 표시해도 됩니다
-- 2022-08-18일의 user_pseudo_id(1997494153.8491999091)은 session_id가 4까지 나옵니다
WITH base AS (
  SELECT
    event_date,
    DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_datetime,
    event_name,
    user_id,
    user_pseudo_id
    -- event_params가 필요하면 UNNEST => PIVOT해서 사용하면 됨
  FROM advanced.app_logs 
  WHERE 
    event_date = "2022-08-18"
    AND user_pseudo_id = "1997494153.8491999091"
  -- WHERE 조건에 이벤트를 필터링해서 계산해도 괜찮음. 여기서는 필터링을 하지 않고, 진행
), diff_data AS (
  SELECT
    *,
    DATETIME_DIFF(event_datetime, prev_event_datetime, SECOND) AS second_diff
    # second_diff 기반으로 새로운 세션의 시작일지, 아닐지를 판단할 수 있음
  FROM (
    SELECT
      *,
      LAG(event_datetime, 1) OVER(PARTITION BY user_pseudo_id ORDER BY event_datetime) AS prev_event_datetime
      # event_datetime이랑 prev_event_datetime을 빼서 20초가 넘으면 새로운 세션으로 정의. 
      # 20초가 넘지 않으면 기존 세션
      -- DATETIME_DIFF() => 차이를 구할 수 있음
    FROM base
  )
)

SELECT
  *,
  # 누적합을 사용해서 session_number를 만들었다!
  SUM(session_start) OVER(PARTITION BY user_pseudo_id ORDER BY event_datetime) AS session_num
  # session을 구할 때 쿼리가 길어질 수 있음. 하루에 접속을 여러번 하는 서비스 => session 기반이 좋을 수 있고, 아니라고 하면 일자별 유저 집계가 나을 수 있다
FROM (
  SELECT
    *, 
    CASE
      WHEN prev_event_datetime IS NULL THEN 1
      WHEN second_diff >= 30 THEN 1 # session을 나누는 기준 초. 데이터를 탐색하면서 결정. 보통 앱 로그에서는 30초, 60초
      ELSE 0
      END AS session_start
      # session이 시작됨을 알리는 session_start
  FROM diff_data
)
ORDER BY event_datetime



답변 1

0

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

윈도우 함수와 관련된 다양한 연습 문제를 풀어보셨네요. 윈도우 함수는 SQL 쿼리에서 데이터 분석을 할 때 매우 유용한 도구입니다. 이러한 연습 문제는 실제로 데이터를 처리하고 분석할 때 매우 도움이 될 것입니다.

비슷한 질문을 다룬 기존 답변과 자료를 참고하여 아래에 공유합니다. 도움이 되길 바랍니다:

  1. 퍼널 분석에서의 윈도우 함수 활용

    • 이 답변에서는 퍼널 분석에서 윈도우 함수를 활용하여 세션 시작 여부를 계산하는 방법을 다루고 있습니다.
  2. 쿼리 작성 시의 가독성 및 효율성 팁

    • 이 질문에서는 쿼리 작성 시 가독성을 높이고 효율적인 쿼리를 작성하는 방법에 대해 설명하고 있습니다.
  3. LAST_VALUE 함수와 UNBOUNDED 사용 예시

    • LAST_VALUE와 UNBOUNDED 프레임을 사용한 예시에 대한 응용 질문입니다.

이 자료들은 윈도우 함수를 다루는 데 있어 더욱 깊이 있는 이해를 도울 수 있으며, 문제를 해결하거나 새로운 인사이트를 얻는 데 도움이 될 것입니다. 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

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

김희은님의 프로필 이미지
김희은

작성한 질문수

질문하기