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

망고맛있어님의 프로필 이미지
망고맛있어

작성한 질문수

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

[인프런 빅쿼리 빠짝스터디 1주차] ARRAY, STRUCT 연습 문제/ PIVOT 연습문제/ 퍼널 쿼리 연습문제

작성

·

81

0

연습문제

(1) Array & Struct


-- 연습문제 1) 영화 제목 별로 장르를 unnest하여 출력
-- select 절에서 새로운 이름으로 사용해야 unnest한 값이 출력됨 (기존의 array칼럼은 사용하지 않기)

select 
  title,
  genre
from`avdanced.array_exercises` as ori
,unnest(genres) as genre 
 
 
 
--연습문제 2) 영화별로 배우와 배역을 출력.
-- safe_offset 사용시, 모든 칼럼에 대하여 일일히 [0], [1].. 해줘야 하는 문제 -> UNNEST 사용.

select 
  title,
  ac.actor,
  ac.character
from`avdanced.array_exercises` as ori
,unnest(actors) as ac 
 

-- 연습문제 3) title, actor, character, genre 출력

select 
  title,
  ac.actor,
  ac.character,
  genre
from`avdanced.array_exercises` as ori
,unnest(actors) as ac 
,unnest (genres) as genre

--연습문제 4) 배열을 풀기

select 
  user_id, 
  event_date,
  event_name,
  user_pseudo_id, 
  eve.key, 
  eve.value.string_value,
  eve.value.int_value
from`avdanced.app_logs_temp` as ori
, unnest (event_params) as eve
where event_date = '2022-08-01'

(2) Pivot 연습문제

--Pivot : 집계함수(if (조건문, true일 때 값, False일때 값)) as new_column + GROUP BY (False일때의 값은 NULL또는 0으로 해주기)
--1) id를 기준으로 amount sum을 pivot, order_date를 행, user_id를  열

-- 연습문제 1-1)  서브쿼리 사용하기 
select
  order_date, 
  sum(if(user_id=1, sum_of_amount, 0)) as user_1,
  sum(if(user_id=2, sum_of_amount, 0)) as user_2,
  sum(if(user_id=3, sum_of_amount, 0)) as user_3
from (
  select 
  order_date,
  user_id, 
  sum(amount) as sum_of_amount
from `avdanced.orders`
group by order_date, user_id
)
group by order_date
order by order_date

-- 연습문제 1-2) 간략하게 작성하기 
select
  order_date, 
  sum(if(user_id=1, amount, 0)) as user_1,
  sum(if(user_id=2, amount, 0)) as user_2,
  sum(if(user_id=3, amount, 0)) as user_3
from `.avdanced.orders`
group by order_date
order by order_date

--연습문제 2) orde_date별로 amount의 합을 pivot (user_id row, drder_date column)
-- (`)backstick을 사용하여 별칭지정
-- any_value: 그룹화할 대상 중 임의의 값을 선택(NULL 제외). any_value에서는 나머지 값이 NULL이거나 확정적으로 이값이 나올 것이다 기대할 때 사용!
-- ANY_VALUE: 임의의 값을 반환하며, 특정한 규칙이나 일관성을 요구하지 않을 때 사용. (대표값, 랜덤 샘플링)
-- MAX: 그룹 내에서 가장 큰 값을 반환하며, 항상 일관된 결과를 제공합니다.

select
  user_id, 
  sum(if(order_date='2023-05-01', amount, 0)) as `2023-05-01`,
  sum(if(order_date='2023-05-02', amount, 0)) as `2023-05-02`,
  sum(if(order_date='2023-05-03', amount, 0)) as `2023-05-03`,
  sum(if(order_date='2023-05-04', amount, 0)) as `2023-05-04`,
  sum(if(order_date='2023-05-05', amount, 0)) as `2023-05-05`
from `avdanced.orders`
group by user_id
order by user_id

-- +) 강의 내용 (any_value)
-- select
--   user_id, 
--   any_value(if(order_date='2023-05-01', amount, 0)) as `2023-05-01`,
--   any_value(if(order_date='2023-05-02', amount, 0)) as `2023-05-02`,
--   any_value(if(order_date='2023-05-03', amount, 0)) as `2023-05-03`,
--   any_value(if(order_date='2023-05-04', amount, 0)) as `2023-05-04`,
--   any_value(if(order_date='2023-05-05', amount, 0)) as `2023-05-05`
-- from `avdanced.orders`
-- group by user_id
-- order by user_id

--연습문제 3) user_id, order_date별로 주문이 있으면 1, 없으면 0으로 pivot, user_id row, order_date column. 
select
  user_id, 
  max(if(order_date='2023-05-01', 1, 0)) as `2023-05-01`,
  max(if(order_date='2023-05-02', 1, 0)) as `2023-05-02`,
  max(if(order_date='2023-05-03', 1, 0)) as `2023-05-03`,
  max(if(order_date='2023-05-04', 1, 0)) as `2023-05-04`,
  max(if(order_date='2023-05-05', 1, 0)) as `2023-05-05`
from `avdanced.orders`
group by user_id
order by user_id

-- 연습문제 4) app_log를 pivot하기
with date_user_cnt as(
select 
  ori.user_id, 
  ori.event_date,
  ori.event_name,
  ori.event_timestamp,
  ori.user_pseudo_id, 
  max(if(eve.key = "firebase_screen", eve.value.string_value, null)) as firebase_screen,
  max(if(eve.key ="food_id", eve.value.int_value, null)) as food_id, 
  max(if(eve.key ="session_id", eve.value.string_value, null)) as session_id
from`avdanced.app_logs_temp` as ori
, unnest (event_params) as eve
where 
   event_date ='2022-08-01'
group by all
)

select 
  event_date, 
  count(user_id) as user_cnt
from date_user_cnt
where
  event_name ="click_cart" 
group by event_date

(3) 퍼널 연습문제

-- 퍼널 별 유저수 집계
-- 1-1) UNNEST하기 & PIVOT하기
WITH base AS(
  SELECT 
    event_date,
    event_timestamp,
    event_name,
    user_id,
    user_pseudo_id,
    MAX(IF(param.key = 'food_id', param.value.int_value,NULL)) AS food_id, 
    MAX(IF(param.key = 'session_id', param.value.string_value,NULL)) AS session_id, 
    MAX(IF(param.key = 'firebase_screen', param.value.string_value,NULL)) AS firebase_screen, 
  from `bigquery-432401.avdanced.app_logs_temp` 
  , unnest (event_params) as param
  where event_date between '2022-08-01' and '2022-08-18'
  GROUP BY ALL
), base2 AS(
-- 1-2) CONCAT하기
  SELECT 
    * EXCEPT (event_name, firebase_screen, event_timestamp),
  CONCAT(event_name, "-", firebase_screen) AS event_name_with_screen,
  DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_datetime
  FROM base
  WHERE
    event_name IN ("screen_view", "click_payment")
), base3 AS (
  --1-3) 일자별 이벤트 별 집계
  SELECT
    event_date, 
    event_name_with_screen,
    CASE 
      WHEN event_name_with_screen = "screen_view-welcome" THEN 1
      WHEN event_name_with_screen = "screen_view-home" THEN 2
      WHEN event_name_with_screen = "screen_view-food_category" THEN 3
      WHEN event_name_with_screen = "screen_view-restaurant" THEN 4
      WHEN event_name_with_screen = "screen_view-cart" THEN 5
      WHEN event_name_with_screen = "click_payment-cart" THEN 6
    ELSE NULL
    END AS step_number,
    COUNT(DISTINCT user_pseudo_id) AS cnt
  FROM base2
  GROUP BY ALL
  HAVING step_number IS NOT NULL
)
--1-4) 집계한 데이터를 PIVOT
SELECT
  event_date,
  MAX(IF(base3.event_name_with_screen ="screen_view-welcome", cnt, NULL)) AS screen_view_welcome,
  MAX(IF(base3.event_name_with_screen ="screen_view-home", cnt, NULL)) AS 	screen_vie_home,
  MAX(IF(base3.event_name_with_screen ="screen_view-food_category", cnt, NULL)) AS screen_view_food_category,
  MAX(IF(base3.event_name_with_screen ="screen_view-restaurant", cnt, NULL)) AS screen_view_restaurant,
  MAX(IF(base3.event_name_with_screen ="screen_view-cart", cnt, NULL)) AS screen_view_cart
FROM base3
GROUP BY ALL

배운점

  • ‘cross join unnest 칼럼 as 별칭’에서 반드시 ‘AS 별칭’ 을 이용해야 ‘Cannot access field on a value with type ARRAY’ 에러가 안 뜬다.

  • 빅쿼리에서는 ‘’이 아닌, ``을 사용하여야 한다.

     

  • pivot이라고 하면 pivot()함수를 반드시 사용해야 편할 것이라고 생각했었는데, max와 if로 pivot을 구현하는 것이 인상 깊었다.

  • SQL 기반이라고 하면 모든 DB가 비슷한 기능을 가지고 있다고 생각했는데, DB마다 생성된 함수 및 기능이 미묘하게 다르다는 것을 느꼈다. 예를 들어 빅쿼리에서 배운 countif()을 MySQL에서 사용했는데 안되는 것도 그 예가 아닐까.

  • 생각보다 빅쿼리와 PostgreSQL에서 사용하는 함수가 동일한 게 많아 인상적이었다.

익숙해져야 할 부분

  • 퍼널 분석을 배우면서, 이론적으로 이해하는 것은 쉽지만 내가 아는 쿼리적인 지식을 실제 데이터에 적용하는 것은 생각보다 손이 많이 가고 쉽지 않은 작업이라는 것을 느꼈다. 많이 해봐야 노하우가 생길 것 같다. 어떤 데이터를 어떻게 해야 어떤 결과가 나오고, 이를 어떻게 이용하고 해석할 수 있는지에 대한 일련의 과정에 익숙해져야 할 것 같다.

  • TIMESTAMP를 DATE로 바꾸고 확인하는 부분에 대한 연습이 필요

     

  • 쿼리 작성 시, 예약어를 대문자로 사용하는 것이 좋다고 알고 있는데, 아직 이 부분이 익숙하지 않아 연습이 필요하다.

  • 코드를 작성하면서 문장을 그대로 쿼리로 옮기는 편이라서 그런지 서브 쿼리를 사용하는 경우가 많다. 단순히 문장을 쿼리로 옮기기 보다 어떻게 하면 더 간결하고 가독성 높은 쿼리를 작성할 수 있을 지 고민하는 습관을 들여야 겠다.

  • 함수 이름 정하는 거 중요한 건 아는데, 잘 안되는 것 같다. 사용 기능을 이용하여 함수 이름 짓는 습관을 지어야겠다.

답변 1

0

안녕하세요, 인프런 AI 인턴입니다. 망고맛있어님.

BigQuery에서 ARRAY, STRUCT, PIVOT 및 데이터 분석을 위한 퍼널 쿼리 작성에 대한 연습을 하고 계시는군요. 다양한 SQL 기능을 어떻게 효과적으로 활용할 수 있는지 연습을 통해 깊이 이해하는 것은 매우 중요합니다. 특히 데이터베이스마다 제공하는 기능이 다르다는 점을 직접 실습을 통해 느끼셨다는 부분이 인상 깊습니다.

제공하신 코드와 정보 보면서 도움이 될 수 있는 유사 질문과 답변들을 아래와 같이 추천드립니다. 같은 주제에 대한 다른 이들의 학습 과정이 망고맛있어님의 이해를 넓히는데 도움이 되길 바랍니다:

  1. ARRAY 및 STRUCT 관리 문제 관련

  2. PIVOT 연습에 대한 질문 및 해결 사례

  3. 퍼널 분석 설계 및 쿼리 작성 관련

    • 퍼널 쿼리 구성 및 오류 확인
      • 퍼널 쿼리 작성 시 발생할 수 있는 문제들에 대해 다루고 있으며, 이 과정에서 개선할 수 있는 힌트를 얻으실 수 있습니다.

각 링크는 여러 대안을 다루고 있으며, 추가적으로 제공된 코드와 비교해보며 발전시킬 수 있는 기회가 될 것입니다.

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

망고맛있어님의 프로필 이미지
망고맛있어

작성한 질문수

질문하기