연습문제 (1) ARRAY, STRUCT -- 1) array_exercises 테이블에서 각 영화(title)별로 장르(genres)를 UNNEST해서 보여주세요 SELECT title , genre FROM advanced.array_exercises CROSS JOIN UNNEST(genres) AS genre -- 2) array_exercises 테이블에서 각 영화(title)별로 배우(actor)와 배역(character)을 보여주세요. 배우와 배역은 별도의 컬럼으로 나와야 합니다 SELECT title, , actor.actor AS actor , actor.character AS character FROM advanced.array_exercises CROSS JOIN UNNEST(actors) AS actor -- 3) array_exercises 테이블에서 각 영화(title)별로 배우(actor), 배역(character), 장르(genre)를 출력하세요. 한 Row에 배우, 배역, 장르가 모두 표시되어야 합니다 SELECT title , actor.actor AS actor , actor.character AS character , genre FROM advanced.array_exercises CROSS JOIN UNNEST(actors) AS actor CROSS JOIN UNNEST(genres) AS genre -- 4) 앱 로그 데이터(app_logs)의 배열을 풀어주세요 SELECT user_id , event_date , event_name , user_pseudo_id , params.key AS key , params.value.string_value AS str_value , params.value.int_value AS int_value FROM advanced.app_logs CROSS JOIN UNNEST(event_params) AS params WHERE event_date = '2022-08-01' (2) PIVOT -- 1) orders 테이블에서 유저(user_id)별로 주문 금액(amount)의 합계를 PIVOT해주세요. 날짜(order_date)를 행(Row)으로, user_id를 열(Column)으로 만들어야 합니다 WITH step1 AS ( SELECT order_date , user_id , sum(amount) AS sum_of_amount FROM advanced.orders GROUP BY ALL ) SELECT order_date , MAX(IF(user_id = 1, sum_of_amount, 0)) AS user_1 , MAX(IF(user_id = 2, sum_of_amount, 0)) AS user_2 , MAX(IF(user_id = 3, sum_of_amount, 0)) AS user_3 FROM step1 GROUP BY order_date ORDER BY order_date -- 2) orders 테이블에서 날짜(order_date)별로 유저들의 주문 금액(amount)의 합계를 PIVOT 해주세요. user_id를 행(Row)으로, order_date를 열(Column)으로 만들어야 합니다 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 advanced.orders GROUP BY user_id ORDER BY user_id -- 3) orders 테이블에서 사용자(user_id)별, 날짜(order_date)별로 주문이 있다면 1, 없다면 0으로 PIVOT 해주세요. user_id를 행(Row)으로, order_date를 열(Column)로 만들고 주문을 많이 해도 1로 처리합니다 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 advanced.orders GROUP BY user_id ORDER BY user_id -- 4) 앱 로그 데이터 배열 PIVOT하기 SELECT user_id , event_date , event_name , user_pseudo_id , MAX(IF(params.key = 'firebase_screen', params.value.string_value, NULL)) AS firebase_screen , MAX(IF(params.key = 'food_id', params.value.int_value, NULL)) AS food_id , MAX(IF(params.key = 'session_id', params.value.string_value, NULL)) AS session_id FROM advanced.app_logs CROSS JOIN UNNEST(event_params) AS params WHERE event_date = '2022-08-01' GROUP BY ALL (3) 퍼널 분석 WITH step1 AS ( SELECT event_date , event_timestamp , event_name , user_id , user_pseudo_id , MAX(IF(params.key = 'firebase_screen', params.value.string_value, NULL)) AS firebase_screen , MAX(IF(params.key = 'session_id', params.value.string_value, NULL)) AS session_id , platform FROM advanced.app_logs CROSS JOIN UNNEST(event_params) AS params WHERE event_date BETWEEN '2022-08-01' AND '2022-08-18' GROUP BY ALL ), step2 AS ( SELECT * EXCEPT(event_timestamp) , CONCAT(event_name, '-', firebase_screen) AS event_name_with_screen , DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_datetime FROM step1 ), step3 AS ( SELECT * , 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 END AS step_number FROM step2 ), step3_1 AS ( -- 1) 각 퍼널별 유저 수 집계 SELECT event_name_with_screen , step_number , COUNT(DISTINCT user_pseudo_id) AS cnt FROM step3 GROUP BY ALL HAVING step_number IS NOT NULL ORDER BY step_number ) , step3_2 AS ( -- 2) 일자별 각 퍼널별 유저 수 집계 SELECT event_date , event_name_with_screen , step_number , COUNT(DISTINCT user_pseudo_id) AS cnt FROM step3 GROUP BY ALL HAVING step_number IS NOT NULL ORDER BY event_date , step_number ) -- 3) 2) 데이터를 PIVOT SELECT event_date , MAX(IF(event_name_with_screen = 'screen_view-welcome', cnt, NULL)) AS `screen_view-welcome` , MAX(IF(event_name_with_screen = 'screen_view-home', cnt, NULL)) AS `screen_view-home` , MAX(IF(event_name_with_screen = 'screen_view-food_category', cnt, NULL)) AS `screen_view-food_category` , MAX(IF(event_name_with_screen = 'screen_view-restaurant', cnt, NULL)) AS `screen_view-restaurant` , MAX(IF(event_name_with_screen = 'screen_view-cart', cnt, NULL)) AS `screen_view-cart` , MAX(IF(event_name_with_screen = 'click_payment-cart', cnt, NULL)) AS `click_payment-cart` FROM step3_2 GROUP BY event_date ORDER BY event_date
1. ARRAY, STRUCT 연습문제 /*1) array_exercise 테이블에서 각 영화(title)별로 장르를 UNNEST 해서 보여주세요*/ select title, genre from `advanced.array_exercises`, unnest(genres) as genre /*2) array_exercise 테이블에서 각 영화별로 배우와 배역을 보여주세요. 배우와 배역은 별도의 칼럼으로 보여주세요*/ select title, actor.actor, actor.character from `advanced.array_exercises`, unnest(actors) as actor /*3) array_exercise 테이블에서 각 영화별로 배우, 배역, 장르를 출력하세요. 한 Row에 배우, 배역, 장르가 모두 표시되어야 합니다.*/ select title, actor.actor, actor.character, genre from `advanced.array_exercises` ,unnest(actors) as actor ,unnest(genres) as genre -- 문제의의도: UNNEST를 2번 연속 사용 가능하다 -- 데이터 중복은 CROSS JOIN으로 인한 어쩔 수 없는 이슈 -- SQL 실행순서 -> FROM -> JOIN -> SELECT -- actors : ARRAY<STRUCT> -> UNNEST -> STRUCT -- genres : ARRAY<STRING> -> UNNEST -> STRING /*4) 앱로그데이터(app_logs)의 배열을 풀어주세요*/ select event_date, datetime(timestamp_micros(event_timestamp),'Asia/Seoul') as event_timestamp, event_name, event_param.key as key, event_param.value.string_value as string_value, event_param.value.int_value as int_value, user_id from `advanced.app_logs` ,unnest(event_params) as event_param -- event_params : ARRAY<STRUCT> -- event_params.value : STRUCT<STRING, INT64> 2. PIVOT 연습문제 /*1) orders 테이블에서 유저별로 주문금액의 합계를 PIVOT해주세요. 날짜를 행으로, user_id를 열로 만들어야합니다. /*case when 사용한 풀이*/ select order_date, sum(case when user_id = 1 then amount else 0 end) as user_1, sum(case when user_id = 2 then amount else 0 end) as user_2, sum(case when user_id = 3 then amount else 0 end) as user_3 from `advanced.orders` group by order_date order by order_date /*if 사용한 풀이*/ 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 `advanced.orders` group by order_date order by order_date /*2) orders 테이블에서 날짜별로 유저들의 주문금액의 합계를 PIVOT 해주세요. user_id를 행으로, order_date를 열로 만들어야 합니다.*/ 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 `advanced.orders` group by user_id order by user_id -- ANY_VALUE: 그룹화할 대상 중 임의의 값(NULL 제외)를 표시한다. -- 나머지 값이 NULL이거나 확정적으로 값이 나올것이라 예상될 때 사용 /*3)orders 테이블에서 사용자별, 날짜별 주문이 있다면 1 없다면 0으로 PIVOT 해주세요. user_id를 행으로 order_date를 칼럼으로 만들고 주문횟수에 상관없이 1로 처리합니다.*/ select user_id, MAX(if(order_date = '2023-05-01' and amount is not null,1,0)) as `2023-05-01`, MAX(if(order_date = '2023-05-02' and amount is not null,1,0)) as `2023-05-02`, MAX(if(order_date = '2023-05-03' and amount is not null,1,0)) as `2023-05-03`, MAX(if(order_date = '2023-05-04' and amount is not null,1,0)) as `2023-05-04`, MAX(if(order_date = '2023-05-05' and amount is not null,1,0)) as `2023-05-05` FROM `advanced.orders` group by user_id order by user_id; /* 횟수를 구해달라고 하는 경우*/ -- MAX를 SUM으로 바꾸면 된다. /*4) APP_LOG PIVOT 실습하기*/ select user_id, event_date, datetime(timestamp_micros(event_timestamp), 'Asia/Seoul') as event_timestamp, event_name, max(if(params.key = 'firebase_screen',params.value.string_value,NULL)) as firebase_screen, max(if(params.key = 'food_id',params.value.int_value,NULL)) as food_id, max(if(params.key = 'session_id',params.value.string_value,NULL)) as session_id from `advanced.app_logs` , unnest(event_params) as params where event_date = '2022-08-01' group by 1,2,3,4 3. 퍼널 분석 연습문제 /* 일자별 퍼널별 유저 수 집계 기간: 2022-08-01 ~ 2022-08-18 사용할 event => event_name과 firebase_screen의 값을 concat하여 사용 1. screen_view-welcome 2. screen_view-home 3. screen_view-food_category 4. screen_view-restaurant 5. screen_view-cart 6. click_payment-cart -- screen_view-welcome에서 user_id는 NULL임 -> user_pseudo_id는 NULL이 아님 -- welcome에서 home으로 넘어가며 로그인을 하여서 그럼 -- WHERE: FROM 절에서 바로 필터링을 하고 싶은 조건을 지정 -- HAVING: GROUP BY 후에 나오는 집계 결과에 대한 조건을 지정 */ with base as ( select event_date, datetime(timestamp_micros(event_timestamp),'Asia/Seoul') as event_timestamp, event_name, user_pseudo_id, max(if(params.key = 'firebase_screen',params.value.string_value,NULL)) as firebase_screen, max(if(params.key = 'food_id',params.value.int_value,NULL)) as food_id, max(if(params.key = 'session_id',params.value.string_value,NULL)) as session_id from `advanced.app_logs` , unnest(event_params) as params where event_date between '2022-08-01' and '2022-08-18' group by 1,2,3,4 ) 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 end as step_number, count(distinct user_pseudo_id) as cnt from ( select *, case when event_name in ('screen_view','click_payment') then concat(event_name,'-',firebase_screen) else null end as event_name_with_screen from base ) group by 1,2,3 having step_number is not null order by event_date, step_number
연습 문제 (1) ARRAY, STRUCT 연습문제 1-1. --1-1) array_exercises 테이블에서 각 영화(title)별로 장르(genres)를 UNNEST해서 보여주세요. SELECT title , genre FROM advanced.array_exercises , unnest(genres) as genre 1-2. --1-2) array_exercises 테이블에서 각 영화(title)별로 배우(actor)와 배역(character)을 보여주세요. 배우와 배역은 별도의 컬럼으로 나와야 합니다. select title , actor.actor , actor.character from advanced.array_exercises , unnest(actors) as actor 1-3. --1-3) array_exercises 테이블에서 각 영화(title)별로 배우(actor), 배역(character), 장르(genre)를 출력하세요. 한 Row에 배우, 배역, 장르가 모두 표시되어야 합니다. select title , actor.actor as actor , actor.character as character , genre from advanced.array_exercises , unnest(actors) as actor , unnest(genres) as genre 1-4. --1-4) 앱 로그 데이터(app_logs)의 배열을 풀어주세요 select user_id , event_date , event_name , user_pseudo_id , param.key as key , param.value.string_value as string_value , param.value.int_value as int_value from advanced.app_logs , unnest(event_params) as param where event_date = '2022-08-01' (2) PIVOT 연습문제 2-1. --2-1) orders 테이블에서 유저(user_id)별로 주문 금액(amount)의 합계를 PIVOT해주세요. 날짜(order_date)를 행(Row)으로, user_id를 열(Column)으로 만들어야 합니다. 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 advanced.orders group by order_date order by order_date 2-2. --2-2) orders 테이블에서 날짜(order_date)별로 유저들의 주문 금액(amount)의 합계를 PIVOT 해주세요. user_id를 행(Row)으로, order_date를 열(Column)으로 만들어야 합니다. select user_id , max(if(order_date = '2023-05-01',amount,0)) as `2023-05-01` , max(if(order_date = '2023-05-02',amount,0)) as `2023-05-02` , max(if(order_date = '2023-05-03',amount,0)) as `2023-05-03` , max(if(order_date = '2023-05-04',amount,0)) as `2023-05-04` , max(if(order_date = '2023-05-05',amount,0)) as `2023-05-05` from advanced.orders group by user_id order by user_id 2-3. --2-3) orders 테이블에서 사용자별, 날짜별로 주문이 있따면 1, 없다면 0으로 PIVOT 해주세요. user_id를 행(Row)으로, order_date를 열(Column)로 만들고 주문을 많이 해도 1로 처리합니다. 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 advanced.orders group by user_id order by user_id 2-4. --2-4) 앱 로그 데이터 배열 PIVOT 하기 select user_id , event_date , event_name , user_pseudo_id , max(if(param.key = 'firebase_screen', param.value.string_value, null)) as firebase_screen , 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 from advanced.app_logs , unnest(event_params) as param where event_date = '2022-08-01' group by all (3) 퍼널 연습문제 3-1. --3-1) 퍼널 별 유저 수 집계(일자별) with base as ( select event_date , event_name , event_timestamp , user_id , user_pseudo_id , platform , max(if(param.key = 'firebase_screen', param.value.string_value, null)) as firebase_screen from advanced.app_logs , unnest(event_params) as param where event_date between '2022-08-01' and '2022-08-18' group by all ), filter_event as ( select * except(event_name, firebase_screen) , concat(event_name, "-", firebase_screen) as event_name_with_screen from base where event_name in ('screen_view', 'click_payment') ) 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 filter_event group by all having step_number is not null order by event_date 3-2. --3-2) 퍼널 별 유저 수 집계 PIVOT with base as ( select event_date , event_name , event_timestamp , user_id , user_pseudo_id , platform , max(if(param.key = 'firebase_screen', param.value.string_value, null)) as firebase_screen from advanced.app_logs , unnest(event_params) as param where event_date between '2022-08-01' and '2022-08-18' group by all ), filter_event as ( select * except(event_name, firebase_screen) , concat(event_name, "-", firebase_screen) as event_name_with_screen from base where event_name in ('screen_view', 'click_payment') ), daily_group as ( 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 filter_event group by all having step_number is not null order by event_date ) select event_date , max(if(event_name_with_screen = 'screen_view-welcome',cnt,null)) as screen_view_welcome , max(if(event_name_with_screen = 'screen_view-home',cnt,null)) as screen_view_home , max(if(event_name_with_screen = 'screen_view-food_category',cnt,null)) as screen_view_food_category , max(if(event_name_with_screen = 'screen_view-restaurant',cnt,null)) as screen_view_restaurant , max(if(event_name_with_screen = 'screen_view-cart',cnt,null)) as screen_view_cart , max(if(event_name_with_screen = 'click_payment-cart',cnt,null)) as click_payment_cart from daily_group group by all order by event_date
1. ARRAY, STRUCT 연습 문제 1-1) ARRAY로 된 genres 컬럼을 평면화해 genre로 alias를 붙이고, title과 CROSS JOIN 하였습니다. SELECT title , genre FROM advanced.array_exercises CROSS JOIN UNNEST(genres) AS genre 1-2) 배우와 배역은 actor컬럼에 ARRAY<STRUCT<actor STRING, character STRING>> 타입으로 저장되어 있습니다. 우선 ARRAY를 평면화하고 .(dot)을 사용해 컬럼을 구분하였습니다. SELECT title , actor.actor , actor.character FROM advanced.array_exercises CROSS JOIN UNNEST(actors) AS actor 1-3) 처음에는 UNNEST 가 익숙하지 않아 단순히 두 데이터의 title을 키 값으로 CTE_ACTOR 테이블에 CTE_GENRE 테이블을 LEFT JOIN 하자는 생각이 들었습니다. WITH CTE_ACTOR AS ( SELECT title , actor.actor AS actor , actor.character AS character FROM advanced.array_exercises CROSS JOIN UNNEST(actors) AS actor ), CTE_GENRE AS ( SELECT title , genre FROM advanced.array_exercises CROSS JOIN UNNEST(genres) AS genre ) SELECT A.title , A.actor , A.character , B.genre FROM CTE_ACTOR A JOIN CTE_GENRE B ON A.title = B.title 강의를 듣고는 CROSS JOIN 을 두 번 해보았습니다. 배열이 각각의 행으로 풀리니 이를 두 번 실행해 결과를 얻을 수 있었고 쿼리도 훨씬 간단해졌습니다 😀 WITH CTE_ACTOR AS ( SELECT title , actor.actor AS actor , actor.character AS character FROM advanced.array_exercises CROSS JOIN UNNEST(actors) AS actor ), CTE_GENRE AS ( SELECT title , genre FROM advanced.array_exercises CROSS JOIN UNNEST(genres) AS genre ) SELECT A.title , A.actor , A.character , B.genre FROM CTE_ACTOR A JOIN CTE_GENRE B ON A.title = B.title 1-4) SELECT user_id , event_date , event_name , user_pseudo_id , event_param.key , event_param.value.string_value , event_param.value.int_value FROM advanced.app_logs , UNNEST(event_params) event_param -- WHERE event_date='2022-08-02' 2. PIVOT 연습문제 2-1) order_date를 기준으로 SUM 을 사용해 유저 별 주문금액 합계를 구하고, 요구사항에 따라 빈 값은 0으로 채웠습니다. 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 advanced.orders GROUP BY order_date 2-2) 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 advanced.orders GROUP BY user_id 2-3) 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 advanced.orders GROUP BY user_id 2-4) SELECT user_id , event_date , event_name , event_timestamp , user_pseudo_id , MAX(IF(event_param.key='firebase_screen', event_param.value.string_value, null)) AS `firebase_screen` , MAX(IF(event_param.key='food_id', event_param.value.int_value, null)) AS `string_value` , MAX(IF(event_param.key='session_id', event_param.value.string_value, null)) `int_value` FROM advanced.app_logs , UNNEST(event_params) event_param WHERE event_date='2022-08-25' AND event_name='click_cart' GROUP BY ALL 3. 퍼널 쿼리 연습 문제 처음엔 CASE 함수를 바로 떠올리지 못해 순서를 저장한 테이블을 만들고 JOIN해 결과를 구했습니다. WITH CTE_STEP AS ( SELECT 'screen_view-welcome' `event_name_with_screen`, 1 `step_number` UNION ALL SELECT 'screen_view-home', 2 UNION ALL SELECT 'screen_view-food_category', 3 UNION ALL SELECT 'screen_view-restaurant', 4 UNION ALL SELECT 'screen_view-cart', 5 UNION ALL SELECT 'click_payment-cart', 6 ), CTE_EVENT AS ( SELECT event_date , event_name_with_screen , COUNT(DISTINCT user_pseudo_id) `cnt` FROM ( SELECT event_date , user_pseudo_id , CONCAT(event_name, '-', event_param.value.string_value) `event_name_with_screen` FROM advanced.app_logs , UNNEST(event_params) `event_param` WHERE event_date BETWEEN '2022-08-01' AND '2022-08-18' AND event_name IN ('screen_view', 'click_payment') AND event_param.key = 'firebase_screen' AND event_param.value.string_value IN ('welcome', 'home', 'food_category', 'restaurant', 'cart') ) GROUP BY event_date , event_name_with_screen ) SELECT A.event_date , A.event_name_with_screen , B.step_number , A.cnt FROM CTE_EVENT A JOIN CTE_STEP B ON A.event_name_with_screen = B.event_name_with_screen ORDER BY event_date, step_number 이후 강의를 참고해 피벗 테이블을 만들고 CASE문을 사용한 쿼리입니다. WITH base AS ( SELECT event_date , event_timestamp , event_name , user_pseudo_id , MAX(IF(event_param.key='firebase_screen', event_param.value.string_value, null)) `firebase_screen` , MAX(IF(event_param.key='session_id', event_param.value.string_value, null)) `session_id` FROM advanced.app_logs , UNNEST(event_params) `event_param` WHERE event_date BETWEEN '2022-08-01' AND '2022-08-18' AND event_name IN ('screen_view', 'click_payment') GROUP BY ALL ), filter_event_and_concat_evnet_and_screen AS ( SELECT * EXCEPT(event_name, firebase_screen, event_timestamp) , CONCAT(event_name, '-', firebase_screen) `event_name_with_screen` , DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') `event_datetime` FROM base WHERE event_name IN ('screen_view', 'click_payment') ) 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) FROM filter_event_and_concat_evnet_and_screen GROUP BY ALL HAVING step_number IS NOT NULL ORDER BY event_date 추가로 결과 테이블을 피벗 테이블로 만들기 위한 쿼리입니다. SELECT event_date , MAX(IF(event_name_with_screen='screen_view-welcome', cnt, 0)) `screen_view-welcome` , MAX(IF(event_name_with_screen='screen_view-home', cnt, 0)) `screen_view-home` , MAX(IF(event_name_with_screen='screen_view-food_category', cnt, 0)) `screen_view-food_category` , MAX(IF(event_name_with_screen='screen_view-restaurant', cnt, 0)) `screen_view-restaurant` , MAX(IF(event_name_with_screen='screen_view-cart', cnt, 0)) `screen_view-cart` , MAX(IF(event_name_with_screen='click_payment-cart', cnt, 0)) `click_payment-cart` FROM result GROUP BY event_date ORDER BY event_date ✔ 느낀 점 쿼리를 작성하기 전 자료형을 파악하자. 요구사항이 헷갈릴 땐 한번에 결과를 내려고 하지말고 단계별로 해결하자. ✔ 새롭게 알게된 점 cmd + D 를 여러 번 해서 같은 단어를 동시에 바꿀 수 있다. group by ALL 을 사용하면 SELECT의 컬럼을 반복해서 적지 않아도 된다. 구글 스프레드 시트에서도 예약 시간을 사용하면 갱신되는 데이터를 제공할 수 있다(예약 시간 주의). 구글 스프레드 시트로 간단한 시각화를 해볼 수 있다. 퍼널 분석에 대한 부분을 재밌게 수강했습니다. 퍼널 분석은 개념 정도만 알고 있었는데 퍼널을 정의하는 것에서 부터 피벗 테이블을 만들고, 시각화하기까지 실무에서의 큰 흐름을 배운 것 같아요. 팀에서 로그 설계를 진행 중인데 완료되면 간단한 퍼널 분석을 시도해보겠습니다💪🏻
ARRAY, STRUCT -- 1) array_exercises 테이블에서 각 영화(title)별로 장르(genres)를 UNNEST해서 보여주세요. select title , genre from advanced.array_exercises as ae cross join unnest ( genres ) as genre ; #pivot 연습문제 — 1 ) 첫번째 풀이 order_date / user_1 / user_2 / user_3 --pivot : max(if(조건, true일 때의 값, false일 때의 값)) as new_colum + group by -- max 대신 집계 함수를 사용할 수도 있음 . sum -- false 일 때의 값은 null select order_date , sum ( if ( user_id = 1 , sum_of_amount , null )) as user_1 , sum ( if ( user_id = 2 , sum_of_amount , null )) as user_2 , sum ( if ( user_id = 3 , sum_of_amount , null )) as user_3 from ( select order_date , user_id , sum ( amount ) as sum_of_amount from advanced.orders group by order_date , user_id ) group by order_date order by 1 ; — 2 ) 두번째 풀이 -- 2번 문제 orders 테이블에서 유저(user_id)별로 주문 금액(AMOUNT)의 합계를 pivot 해주세요. -- 날짜(order_date)를 행(row)으로 user_id를 열 (column)으로 만들어야 합니다 -- 컬럼의 이름을 지정할 때 영어 제외하고 backtick('') option + ~ select user_id , max ( if ( order_date = "2023-05-01" , amount , 0 )) as 2023 - 05 - 01 , max ( if ( order_date = "2023-05-02" , amount , 0 )) as 2023 - 05 - 02 , max ( if ( order_date = "2023-05-03" , amount , 0 )) as 2023 - 05 - 03 , max ( if ( order_date = "2023-05-04" , amount , 0 )) as 2023 - 05 - 04 , max ( if ( order_date = "2023-05-05" , amount , 0 )) as 2023 - 05 - 05 from advanced.orders group by 1 order by 1 -- 3번 문제 orders 테이블에서 사용자(user_id)별, 날짜(order_date)별 주문이 있다면 1, -- 없다면 0 으로 pivot 해주세요. user_id를 행(row)으로 order_date를 열 (column)으로 만들어야 합니다 -- 컬럼의 이름을 지정할 때 영어 제외하고 backtick('') option + ~ 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 advanced.orders group by 1 order by 1
UNNEST 1) array_exercises 테이블에서 각 영화(title)별로 장르를(genres) unnest 해서 보여주세요 SELECT title, genre FROM advanced.array_exercises CROSS JOIN UNNEST(genres) AS genre 2) array_exercieses 테이블에서 각 영화(title) 별로 배우 (actor)와 배역(character)을 보여주세요. 배우와 배역은 별도의 컬럼으로 나와야 합니다. SELECT title, actor_info.actor, actor_info.character, FROM advanced.array_exercises CROSS JOIN UNNEST(actors) AS actor_info; actors는 하나의 배열이고 그 배열의 각 요소가 STRUCT(구조체) 배열 자체에서 바로 .actor나 .character로 접근할 수 없음 먼저 배열을 UNNEST로 펼친 후에 펼쳐진 각 STRUCT에서 필드값 을 가져와야함 actors는 '서류 묶음'(배열) 각 서류(STRUCT)에는 '배우 이름'과 '캐릭터 이름'이라는 항목이 있음 서류 묶음을 먼저 풀어서(UNNEST) 개별 서류로 만든 다음 각 서류에서 원하는 정보를 읽어야 함 3) array_exercises 테이블에서 각 영화(title) 별로 배우(actor), 배역(character), 장르(genre)를 출력하세요. 한 row 에 배우, 배역, 장르가 모두 표시되어야 합니다. SELECT title, actor_info.actor, actor_info.character, genre, FROM advanced.array_exercises CROSS JOIN UNNEST(actors) AS actor_info CROSS JOIN UNNEST(genres) AS genre; actors 는 배열 인데 구조에 그 밑에 스트링, 스트링 2개 항목이 저장된거고 genres 는 배열인데 스트링 한 계층?의 구조가 있는거라 서로 구조가 달라서 둘이 같이 unnest 불가함 그래서 cross join, unnest 두 번 써줘야함 actors : ARRAY<STRUCT> => UNNEST => STRUCT genres : ARRAY<STRING> => UNNEST => STRING 4) 앱 로그 데이터(app_logs)의 배열을 풀어주세요. SELECT user_id, event_date, event_name, user_pseudo_id, params.key AS key, params.value.string_value AS string_value, params.value.int_value AS int_value, FROM advanced.app_logs CROSS JOIN UNNEST(event_params) AS params ORDER BY event_date; 2022.08.01 부터 나와있길래 그때 날짜부터 정렬인줄 알았더니 where 절에서 2022.08.01 로 필터링 한거였음;; 에러 메시지의 의미: "Expected end of input but got keyword UNNEST" → FROM 절 다음에 UNNEST가 바로 나오면 안 되고, JOIN이나 CROSS JOIN이 먼저 나와야 한다는 뜻 JOIN이나 CROSS JOIN이 필요한 이유: 원본 테이블(app_logs)의 행과 UNNEST로 펼친 배열(event_params)의 요소들을 어떻게 연결할지 명시해야 하기 때문 PIVOT 1) orders 테이블에서 유저(user_id)별로 주문금액(amount)의 합계를 PIVOT 해주세요 날짜(order_date)를 행(Row)으로, user_id를 열(Column)으로 만들어야 합니다. 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 advanced.orders GROUP BY order_date ORDER BY order_date ASC 첫번째 풀이는 PIVOT을 하면서 바로 SUM을 한 것 다른 풀이는 집계 함수를 사용해서(SUM) 집계한 후에 PIVOT 컬럼 별칭(AS)에 작은따옴표를 사용함 (AS '2023-05-01') → 백틱 `` 을 사용해야 함. GROUP BY 절에 직접 ASC/DESC를 사용함 → ORDER BY를 따로 사용해야 함 2) orders 테이블에서 날짜(order_date)별로 유저들의 주문금액(amount)의 합계를 PIVOT 해주세요. user_id를 행으로, order_date를 열으로 만들어야 합니다. 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 advanced.orders GROUP BY user_id ORDER BY user_id; 3) orders 테이블에서 사용자(user_id)별, 날짜(order_date)별로 주문이 있다면 1, 없다면 0으로 PIVOT 해주세요. user_id를 행으로, order_date를 열로 만들고 주문을 많이 해도 1로 처리합니다. 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 advanced.orders GROUP BY user_id ORDER BY user_id 주문 횟수별로 구해달라고 했을 땐? → MAX 대신 SUM 값이 있으면 1로 넣어달라고 했기 때문에 이걸 SUM 하면 주문 횟수 더한 값이 됨. 4) user_id = 32888 이 카트 추가하기 (click_cart)를 누를 때 어떤 음식(food_id)을 담았나요? WITH base AS ( SELECT event_date, event_name, user_pseudo_id, event_timestamp, user_id, MAX(IF(param.key = "firebase_screen", param.value.string_value, NULL)) AS firebase_screen, 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 FROM advanced.app_logs CROSS JOIN UNNEST(event_params) AS param WHERE event_date = "2022-08-01" GROUP BY ALL ) SELECT select_date, COUNT(user_id) AS user_cnt FROM base WHERE event_name = "click_cart" GROUP BY event_date
ARRAY, STRUCT 연습문제 -- 1. array_exercises 테이블에서 title 별로 genres를 UNNEST하기 SELECT title , genre FROM advanced.array_exercises CROSS JOIN UNNEST(genres) as genre; -- 2. array_exercises 테이블에서 title 별로 actor, character 추출 -- actor, character는 별도의 컬럼으로 빼기 (struct의 key로써 존재하면 안 됨.) SELECT title , ACTORS.actor AS actor , ACTORS.character AS character FROM advanced.array_exercises CROSS JOIN UNNEST(actors) AS ACTORS; -- 3. array_exercises 테이블에서 title 별로 actor, character, genre 추출 -- 여러 ARRAY 컬럼을 UNNEST할 경우, 각 컬럼별로 UNNEST한 것을 CROSS JOIN 진행하면 됨. SELECT title , ACTORS.actor AS actor , ACTORS.character AS character , genre FROM advanced.array_exercises CROSS JOIN UNNEST(actors) AS ACTORS CROSS JOIN UNNEST(genres) as genre; -- 4. app_logs 테이블(약 73만 건의 로그 데이터)의 ARRAY를 UNNEST 하기 -- event_params 형태? -- ARRAY<STRUCT<key STRING, value STRUCT<string_value STRING, int_value INT64>>>[ -- STRUCT('firebase_screen', STRUCT('food_detail', NULL)) -- , ... -- ] SELECT user_id , event_date , event_name , user_pseudo_id , EVENT_PARAMS.key AS key , EVENT_PARAMS.value.string_value AS string_value , EVENT_PARAMS.value.int_value AS int_value FROM advanced.app_logs CROSS JOIN UNNEST(event_params) AS EVENT_PARAMS PIVOT 연습문제 -- 1. 날짜별 유저별 주문금액 합계 -- 첫번째 그룹 axis는 GROUP BY 대상 컬럼임. (여기서는 '날짜별'에 해당함.) -- 두번째 그룹 axis는 IF 혹은 CASE WHEN을 이용하여 각 컬럼으로 만들어야 함. (여기서는 '유저별'에 해당함.) -- 세번째 그룹 axis는 두번째 그룹 axis를 다루는 과정에서 '값'으로 들어가야 함. (여기서는 '주문금액'에 해당함.) 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 `advanced.orders` WHERE 1=1 AND user_id IN (1,2,3) GROUP BY order_date ORDER BY order_date ASC; -- 2. 유저별 날짜별 주문금액 합계 -- 문자열을 결과 컬럼으로 넣기 위해선 백틱(`)으로 감싸기!! 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 `advanced.orders` WHERE 1=1 AND user_id IN (1,2,3) AND order_date IN ('2023-05-01','2023-05-02','2023-05-03','2023-05-04','2023-05-05') GROUP BY user_id ORDER BY user_id ASC; -- 3. 유저별 날짜별 주문내역 존재여부 -- 주문 존재하면 1, 없으면 0; 주문횟수가 아님에 유의 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 `advanced.orders` WHERE 1=1 AND user_id IN (1,2,3) AND order_date IN ('2023-05-01','2023-05-02','2023-05-03','2023-05-04','2023-05-05') GROUP BY user_id ORDER BY user_id ASC; -- 4. app_logs 테이블 PIVOT 하기 -- user_id=32888이 카트 추가하기(click_cart)를 누를 때 어떤 음식(food_id)를 담았나요? -- 일반화된 문제 정의: 유저별 이벤트별 이벤트 파라미터 key-value 보기 -- 특정 유저가 특정 action을 취했을 때 (event가 발생했을 때) 앱 내부적으로 어떤 정보가 오갔는지 보고싶을 때 -- 방법 1) 쪼개서 생각하기 WITH base AS ( -- step 1) app_logs 테이블은 ARRAY 컬럼이 존재하는 테이블: UNNEST 하기 → UNNEST한 테이블을 임시테이블화 SELECT event_date, event_timestamp, event_name, params.key AS key_, params.value.string_value AS string_value_, params.value.int_value AS int_value_, user_id, user_pseudo_id, platform FROM advanced.app_logs CROSS JOIN UNNEST(event_params) AS params WHERE 1=1 -- AND user_id=32888 -- AND event_name='click_cart' AND event_date >= '2022-08-01' AND event_date <= '2022-08-31' ) -- step 2) event_params에 대해 PIVOT 진행 SELECT user_id, event_date, event_name, event_timestamp, user_pseudo_id, MAX(IF(key_='food_id',int_value_,NULL)) AS `food_id`, MAX(IF(key_='session_id',string_value_,NULL)) AS `session_id`, MAX(IF(key_='firebase_screen',string_value_,NULL)) AS `firebase_screen`, FROM base GROUP BY user_id, event_date, event_name, event_timestamp, user_pseudo_id; -- 방법 2) UNNEST + PIVOT을 한 쿼리에 WITH base AS ( SELECT user_id, event_date, event_name, event_timestamp, user_pseudo_id, MAX(IF(params.key='food_id',params.value.int_value,NULL)) AS `food_id`, MAX(IF(params.key='session_id',params.value.string_value,NULL)) AS `session_id`, MAX(IF(params.key='firebase_screen',params.value.string_value,NULL)) AS `firebase_screen`, FROM advanced.app_logs CROSS JOIN UNNEST(event_params) AS params GROUP BY ALL ) -- user_id=32888이 카트 추가하기(click_cart)를 누를 때 어떤 음식(food_id)을 담았나요? SELECT * FROM base WHERE 1=1 AND user_id=32888 AND event_name='click_cart'; 퍼널 쿼리 연습문제 WITH main AS ( SELECT event_date, CONCAT(event_name,'-', event_param.value.string_value) AS event_name_with_screen, CASE WHEN event_name = 'screen_view' AND event_param.value.string_value = 'welcome' THEN 1 WHEN event_name = 'screen_view' AND event_param.value.string_value = 'home' THEN 2 WHEN event_name = 'screen_view' AND event_param.value.string_value = 'food_category' THEN 3 WHEN event_name = 'screen_view' AND event_param.value.string_value = 'restaurant' THEN 4 WHEN event_name = 'screen_view' AND event_param.value.string_value = 'cart' THEN 5 WHEN event_name = 'click_payment' AND event_param.value.string_value = 'cart' THEN 6 END AS step_num, COUNT(DISTINCT user_pseudo_id) AS cnt FROM advanced.app_logs CROSS JOIN UNNEST(event_params) AS event_param WHERE 1=1 AND event_date BETWEEN '2022-08-01' AND '2022-08-18' AND event_param.key = 'firebase_screen' AND event_name IN ("screen_view",'click_payment') GROUP BY 1,2,3 HAVING step_num IS NOT NULL ) SELECT event_date, SUM(IF(step_num = 1, cnt, 0)) AS `screen_view-welcome`, SUM(IF(step_num = 2, cnt, 0)) AS `screen_view-home`, SUM(IF(step_num = 3, cnt, 0)) AS `screen_view-food_category`, SUM(IF(step_num = 4, cnt, 0)) AS `screen_view-restaurant`, SUM(IF(step_num = 5, cnt, 0)) AS `screen_view-cart`, SUM(IF(step_num = 6, cnt, 0)) AS `click_payment-cart` FROM main GROUP BY 1 ORDER BY event_date ASC
안녕하세요. 다익스트라는 에지의 가중치가 양수일때 출발노드에서 전체 각 노드까지의 최단거리, 벨만-포드는 특정 출발노드에서 다른 노드까지의 최단 경로 탐색, 음수 가중치가 있어도 수행 가능 이렇게 되어있는데, 벨만-포드에서 에지 사용 횟수를 강조하는 이유가 다익스트라는 출발 노드가 정해져있고, 벨만-포드는주어진 출발노드가 달라질수 있어서라고 생각하면 될까요..? 처음엔 가중치 양수, 음수만의 차이만 인줄 알았는데, 뭔가 강조하시는걸 보니 저런 이유때문인가하고 질문해봅니다..! 다들 화이팅
n,m=map(int,input().split()) weight=list(map(int, input().split())) left=0 right=(n-1) cnt=0 weight.sort() while left<=right: weight_sum=weight[left]+weight[right] if weight_sum>m: cnt+=1 right-=1 else: cnt+=1 left+=1 right-=1 print(cnt) 안녕하세요 선생님, 이렇게 left, right 포인터를 이용해서 풀어도 예제 문제는 모두 정답이 나오는데 혹시 이렇게 푸는 풀이도 답으로 가능할까요?
안녕하세요. 좋은 강의 감사합니다! a와 b의 최대 공약수 시간 복잡도에 대해 질문이 있는데요. 약수를 구하는 시간 복잡도가 O(√n)이고, 최대 공약수를 구하기 위해서는 a, b 각각의 약수를 구하는 연산이 들어가기 때문에 최소 O(√a + √b)가 될 텐데 어떻게 O(√max(a, b))가 나오게 되는지 궁금합니다.
현재 섹션 5의 3번째 영상을 보고 있습니다. category = models.ForeignKey( Category, on_delete=models.CASCADE, db_constraint=False, ) 위 코드에서 카테고리에 왜 db_constraint=False, 를 설정하였는지 이해가 잘 되지 않아 설정 용도에 대해 알고 싶습니다. default=null을 한다면, 카테고리 외래키 없이 product 데이터를 생성할 목적인걸 알겠는데, 없는 상황에서 어떤 이유에 사용하신 것인지 알고 싶습니다.
SELECT [1, 2, 3, 4, 5] AS some_numbers ; SELECT ARRAY<INT64>[1, 2, 3, 4, 5] AS some_numbers ; SELECT GENERATE_ARRAY(1, 5, 1) AS some_numbers ; SELECT [SAFE_OFFSET()] ; SELECT (1, 2, 3) AS struct_test ; SELECT STRUCT<hi INT64, hello INT64>(1, 2) AS struct_test ; SELECT a.title, b AS genre FROM workspace.array_exercises AS a JOIN UNNEST(genres) AS b ; SELECT a.title, b.actor, b.character FROM workspace.array_exercises AS a JOIN UNNEST(actors) AS b ; SELECT a.title, b.actor, b.character, c AS genre FROM workspace.array_exercises AS a JOIN UNNEST(actors) AS b JOIN UNNEST(genres) AS c ; SELECT a.user_id, a.event_date, a.event_name, a.user_pseudo_id, b.key, b.value.string_value, b.value.int_value FROM workspace.app_logs AS a JOIN UNNEST(event_params) AS b ; SELECT key, string_value, count(distinct user_pseudo_id) FROM ( SELECT a.user_id, a.event_date, a.event_name, a.user_pseudo_id, b.key, b.value.string_value, b.value.int_value FROM workspace.app_logs AS a JOIN UNNEST(event_params) AS b ) WHERE event_name = 'screen_view' GROUP BY ALL ; 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 workspace.orders GROUP BY ALL ORDER BY order_date ; SELECT user_id, sum(if(order_date = '2023-05-01', amount, 0)) `2023-05-01`, sum(if(order_date = '2023-05-02', amount, 0)) `2023-05-02`, sum(if(order_date = '2023-05-03', amount, 0)) `2023-05-03`, sum(if(order_date = '2023-05-04', amount, 0)) `2023-05-04`, sum(if(order_date = '2023-05-05', amount, 0)) `2023-05-05` FROM workspace.orders GROUP BY ALL ORDER BY user_id ; SELECT user_id, if(sum(if(order_date = '2023-05-01', amount, 0)) > 0, 1, 0) `2023-05-01`, if(sum(if(order_date = '2023-05-02', amount, 0)) > 0, 1, 0) `2023-05-02`, if(sum(if(order_date = '2023-05-03', amount, 0)) > 0, 1, 0) `2023-05-03`, if(sum(if(order_date = '2023-05-04', amount, 0)) > 0, 1, 0) `2023-05-04`, if(sum(if(order_date = '2023-05-05', amount, 0)) > 0, 1, 0) `2023-05-05` FROM workspace.orders GROUP BY ALL ORDER BY user_id ; WITH events AS ( SELECT event_date, event_timestamp, event_name, user_id, user_pseudo_id, platform, MAX(IF(b.key = "firebase_screen", b.value.string_value, NULL)) AS firebase_screen, MAX(IF(b.key = "session_id", b.value.string_value, NULL)) AS session_id FROM workspace.app_logs AS a JOIN UNNEST(event_params) AS b WHERE event_date >= '2022-08-01' AND event_date < '2022-08-19' GROUP BY ALL ), filter_event_and_concat_event_and_screen AS ( 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 events WHERE event_name IN ('screen_view', 'click_payment') ) 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 END AS step_number, COUNT(DISTINCT user_pseudo_id) AS cnt FROM filter_event_and_concat_event_and_screen GROUP BY ALL HAVING step_number IS NOT NULL ;