리텐션 SQL 쿼리 작성하기, Weekly와 Monthly 쿼리를 작성한 부분을 게시판에 올립니다. -- Weekly 리텐션 작성하기. 마지막 부분 , analysis AS (SELECT diff_of_week, user_cnt, FIRST_VALUE(user_cnt) OVER (ORDER BY diff_of_week) AS first_user_cnt FROM (SELECT diff_of_week, COUNT(DISTINCT user_pseudo_id) AS user_cnt FROM first_date_and_diff GROUP BY 1)) SELECT diff_of_week, user_cnt, ROUND(SAFE_DIVIDE(user_cnt, first_user_cnt), 3) AS retention_week_rate FROM analysis ORDER BY 1; -- 월별 리텐션 계산 WITH base AS ( SELECT DISTINCT user_pseudo_id, event_name, DATE(DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul')) AS event_date, DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_datetime, FROM advanced.app_logs WHERE event_date BETWEEN '2022-08-01' AND '2022-11-03' ), first_date_and_diff AS ( SELECT *, DATE_DIFf(event_month, first_month, MONTH) AS diff_of_month FROM ( SELECT DISTINCT user_pseudo_id, DATE_TRUNC(MIN(event_date) OVER(PARTITION BY user_pseudo_id), MONTH) AS first_month, DATE_TRUNC(event_date, MONTH) AS event_month FROM base ) ), analysis AS ( SELECT diff_of_month, user_cnt, FIRST_VALUE(user_cnt) OVER(ORDER BY diff_of_month) AS first_user_cnt FROM ( SELECT diff_of_month, COUNT(DISTINCT user_pseudo_id) AS user_cnt FROM first_date_and_diff GROUP BY 1 ) ) SELECT diff_of_month, user_cnt, ROUND(SAFE_DIVIDE(user_cnt, first_user_cnt), 3) AS retention_month_rate FROM analysis
안녕하세요. 저는 이번에 마지막 문제를 응용해서, 퍼널별로 유저들의 새로운 세션 시작 횟수의 총합을 계산 해보았습니다. [결과 그래프] 새로운 세션 시작 기준: 이전 세션 시간 대비 20초 이상이 지나면, 새로운 세션을 활성화했다고 가정 (강의 내용과 동일) 첫번째 강의에서 배운, UNNEST 문법과 PIVOT 을 하는 방법을 활용해서, event_params에 있는 firebase_screen의 string_value 값을 새로운 열인 firebase_screen 이라고 만듭니다. 전체 데이터를 조회하면, 쿼리 비용이 많이 들기 때문에, where 조건 절로 값을 작게 명시해줍니다. WITH base AS ( SELECT event_date, DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_timestamp, event_name, user_pseudo_id, MAX(IF(ep.key = 'firebase_screen', ep.value.string_value, NULL)) AS firebase_screen FROM advanced.app_logs CROSS JOIN UNNEST(event_params) AS ep WHERE event_date = '2022-08-18' AND user_pseudo_id = '5464646449.4088767327' GROUP BY ALL ) LAG() 함수를 사용하여, 이전 날짜 값을 가져옵니다. 이 때, 퍼널별로 구해야하기 때문에, PARTITION BY에 firebase_screen 을 써줍니다. 그 후, DATETIMEDIFF 함수를 사용해서, 현재값과 이전값의 차이를 계산합니다. WITH base AS ( SELECT event_date, DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_timestamp, event_name, user_pseudo_id, MAX(IF(ep.key = 'firebase_screen', ep.value.string_value, NULL)) AS firebase_screen FROM advanced.app_logs CROSS JOIN UNNEST(event_params) AS ep WHERE event_date = '2022-08-18' AND user_pseudo_id = '5464646449.4088767327' GROUP BY ALL ), diff_funnel_time AS ( SELECT *, DATETIME_DIFF(event_timestamp, prev_event_timestamp, SECOND) AS second_diff FROM ( SELECT *, LAG(event_timestamp, 1) OVER(PARTITION BY firebase_screen ORDER BY event_timestamp) AS prev_event_timestamp FROM base ) ) SELECT * FROM diff_funnel_time 3. ROW_NUMBER() 함수를 사용해서, 퍼널별로 순서를 매깁니다. 그 후, second_diff 의 값이 NULL인 경우는 해당 퍼널의 첫 시작 위치를 가리키므로 1을 넣어주고, rn > 1이고 second_diff >= 20인 경우는 1을 넣어줍니다. 이 때 funnel_per_session_start 컬럼은 퍼널별로 새로운 세션이 시작했는지 여부를 가리킵니다. , funnel_start AS ( SELECT *, CASE WHEN second_diff IS NULL THEN 1 WHEN rn > 1 AND second_diff >= 20 THEN 1 ELSE 0 END AS funnel_per_session_start FROM ( SELECT *, ROW_NUMBER() OVER(PARTITION BY firebase_screen ORDER BY event_timestamp) AS rn FROM diff_funnel_time ) ) 이제, 퍼널별로 세션 시작 여부를 SUM()하고, GROUP BY를 해줍니다. SELECT firebase_screen, SUM(funnel_per_session_start) AS funnel_per_session_start_cnt FROM funnel_start GROUP BY ALL ORDER BY 2 DESC; WHERE 조건절을 주석처리하고, 전체 데이터에 대해서, 집계해봅니다. WITH base AS ( SELECT event_date, DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_timestamp, event_name, user_pseudo_id, MAX(IF(ep.key = 'firebase_screen', ep.value.string_value, NULL)) AS firebase_screen FROM advanced.app_logs CROSS JOIN UNNEST(event_params) AS ep -- WHERE -- event_date = '2022-08-18' -- AND user_pseudo_id = '5464646449.4088767327' GROUP BY ALL ), diff_funnel_time AS ( SELECT *, DATETIME_DIFF(event_timestamp, prev_event_timestamp, SECOND) AS second_diff FROM ( SELECT *, LAG(event_timestamp, 1) OVER(PARTITION BY firebase_screen ORDER BY event_timestamp) AS prev_event_timestamp FROM base ) ) , funnel_start AS ( SELECT *, CASE WHEN second_diff IS NULL THEN 1 WHEN rn > 1 AND second_diff >= 20 THEN 1 ELSE 0 END AS funnel_per_session_start FROM ( SELECT *, ROW_NUMBER() OVER(PARTITION BY firebase_screen ORDER BY event_timestamp) AS rn FROM diff_funnel_time ) ) SELECT firebase_screen, SUM(funnel_per_session_start) AS funnel_per_session_start_cnt FROM funnel_start GROUP BY ALL ORDER BY 2 DESC;
안녕하세요. 강의를 잘 듣고 있습니다. 다름이 아니라, 연습문제를 모두 풀고 나서 윈도우함수 강의를 듣는 과정에서, default에 대해 궁금한 점이 생겼습니다. 정확히, 계산을 해야할 경우, 중복된 데이터가 있는 경우를 고려해서, ROWS BETWEEN UNBOUNDED PRECEDINIG AND CURRENT ROW 라고 프레임의 범위를 정확하게 명시를 하는 것이 좋을 것 같다. 라는 생각이 들었습니다. 그 이유는 다음과 같습니다. 강의에서 말씀해주신대로, 구글 빅쿼리는 default 값이 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 라고 되어있는데요, -- 4) -- 누적 쿼리: 과거의 시간(UNBOUNDED PRECEDING)부터 current row까지 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 ) -- QUALIFY cumulative_sum != cumulative_sum2 ORDER BY user, query_date 문득, default값이 RANGE BETWEEN UNBOUND PRECEDING AND CURRENT ROW 라면, 왜 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 와 같은 값을 가질까? 다른 값을 가지는 경우도 있지 않을까? 하는 의문이 들었습니다. 예제에서는, GROUP BY ALL을 했기 때문에, 중복 데이터가 있어도, query_cnt로 집계가 된 상태에서, 윈도우 함수를 실행하다보니, QUALIFY로 조건절 검증을 수행해도, != 를 만족하는 데이터가 없었던 것 같았습니다. 그래서, 1번 예제와 4번 예제를 결합해서, 다음과 같이 검증을 수행해보았습니다. -- INSERT INTO my_sess.query_logs (user, team, query_date) -- VALUES ('샘', 'Data Science', '2024-04-24'); SELECT *, -- 시간의 흐름에 따라, 일자별 유저가 실행한 누적 총 쿼리 수 SUM(total_query_cnt) OVER(PARTITION BY user ORDER BY query_date) AS cumulative_total_sum, SUM(total_query_cnt) OVER(PARTITION BY user ORDER BY query_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS cumulative_total_sum2 FROM ( SELECT *, -- 사용자별 시간의 흐름에 따라 쿼리를 실행한 총 횟수: total_query_cnt COUNT(query_date) OVER(PARTITION BY user) AS total_query_cnt FROM my_sess.query_logs ) -- QUALIFY cumulative_total_sum != cumulative_total_sum2 ORDER BY user, query_date 결과는 다음과 같습니다. 중복데이터가 있을 경우, RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW는 다 합쳐서 하나로 집계해서 결과값을 내놓는 것으로 보입니다. QUALIFY 함수를 적용했을 때 cumulative_total_sum = cumulative_total_sum2 인 경우 데이터 중복이 없을 경우에는, 같은 값이 나옵니다.
안녕하세요. 이어서, 윈도우 함수에 대해서 잘 듣고 있습니다.Bigquery PDF파일의 P.229페이지를 보면, LAST_VALUE 에 대해서, 쿼리 값이 있는데요, LAST_VALUE가 각 파티션을 나눈 user_id의 마지막 값(1004의 경우, 8, 2112의 경우 7, 3912의 경우 4)를 가져오려면, UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING 값이 들어가야 합니다.그 이유가, 해당 FRAME이 따로 정의되어있지 않으면, 다음과 같은 값이 나옵니다. 섹션 2-4 윈도우 함수 탐색 함수 연습 문제에서, FIRST_VALUE, LAST_VALUE로도 한번 쿼리 작성을 해보라는 연습을 해보라고 하셔서, 연습하는 도중에 발견하게 되었습니다. 이번에는 UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING 을 추가해보겠습니다.
안녕하세요. 빅쿼리를 좀 더 공부하고 싶어, 강의를 결제하게 되었습니다. 다름이 아니라, app_logs_temp 데이터를 강의에서 알려준대로, upload 하고 테이블을 만들었을 떄는 정상적으로, 잘 표시가 되는데요, 문제는 event_date 를 기준으로 (날짜 기반 파티셔닝)을 했을 때, 데이터가 0B가 되는 문제가 발생합니다! Array, Struct 문제에서 4번 문제를 풀때, "데이터를 표시할 수 없다" 라는 말이 있어서, 왜 이럴까.. 하다가, 발견하게 되었어요.. 저는 이미 예전에 빅쿼리를 사용해본 적이 있어서, billing account 계정이 모두 연결된 상태이구요. chatgpt 말로는 이 방법도 안된다면, 빈 파티셔닝 테이블 만들어 놓고 INSERT INTO로 하나하나 데이터 넣으라는데... 예전에 프로젝트 할 때, 이 방법으로 했다가 돈이 꽤 나와서요.. 어떻게 해야할까요?
https://github.com/nadazelda/androidKotlinStudy.git 노트북에서 가상머신 띄우기엔 너무 느려서;; 제 개인 핸드폰으로 실행하는데 firebase 연결이 안되고 있어요 git에 소스 올려뒀습니다 _ori가 강의자료고 mysololife 가 지금 제가 작성하는거에요
안녕하세요 강의 재밌게 잘 따라가고 있는데요, 궁금한 점이 있어서 첫 질문 올리게 되었습니다. Login 페이지 테스트 시 이메일이나 패스워드 관련해서 잘못된 부분이 있으면 사진과 같이 하단에 메시지가 표시되는데요, 이 메시지는 어디서 발생하는 메시지인지?(FF or Firebase) 그리고 규칙(자리수, 이메일 포맷 등등)이나 문구를 바꾸려면 어떻게 해야하는지 알려주시면 감사하겠습니다.
안녕하세요 로펀입니다. 강의를 수강하시면서 공지사항과 질문을 편하게 관리하기 위해 슬랙 채널을 개설했습니다 🙂 강의와 관련된 질문이 있으실 경우 슬랙의 #supabase-nextjs-클론-강의 채널에서 질문 부탁드립니다. 💡 ”로펀의 인프런 상담소” 슬랙 채널 가입하기 제 강의를 수강하시는 모든 분들은 슬랙 채널에 들어오실 수 있습니다. 슬랙에 들어오시면 더 빠르게 질문에 답변을 받아보실 수 있어요! 😉