게시글
질문&답변
코칭 관련
홍주님 안녕하세요! 네 여전히 가능합니다!급하게 마감되진 않을 것 같아서 강의 듣고 신청해주셔요!!
- 0
- 2
- 22
질문&답변
array 등
안녕하세요!배열 함수를 자주 접하신 적이 없으면 생소할 수 있습니다. 우선 BigQuery의 Array 데이터는 Google Analytics4나 Firebase를 사용하는 회사에서는 자주 볼 수 있습니다. GA4나 Firebase를 배열로 데이터를 저장하기 때문에 이걸 사용하지 않으면 데이터를 풀 수 없습니다. 그럼 BigQuery만의 특수한 문법이 아닌가?라고 생각할 수 있는데, 전통적인 OLTP에서는 배열 데이터가 없기도 합니다. 예를 들어 MySQL에서는 배열 함수가 없고, JSON 형태를 활용해서 만들어야 합니다. 예시는 링크에서 확인할 수 있습니다. 그 외에 PostgreSQL에는 배열이 있습니다. BigQuery에서 사용하는 ARRAY 관련 함수를 볼 수 있습니다.공식 문서 : https://www.postgresql.org/docs/current/arrays.html 데이터 웨어하우스(DW) 계열에서는 배열 데이터가 많이 활용됩니다. 여러 데이터를 저장해야 할 때, 배열 형태로 데이터를 저장하곤 합니다(파이썬의 List처럼) 그리고 그걸 활용할 때 배열을 사용하게 됩니다. Snowflake 문서 : https://docs.snowflake.com/ko/sql-reference/functions/array_aggSpark 문서 : https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.array.html 데이터 저장하는 형태가 복잡해지면 배열은 한번 쯤은 경험하게 되는 것 같아요. 사용자 앱 로그 데이터를 저장할 때는 배열 형태로 저장하는 것이 수월한 경우도 꽤 있었어요. 파이썬에서도 Dict, List가 존재하는데 데이터를 어떻게 저장해야 하느냐에 따라 적절하게 활용하곤 합니다. 데이터베이스, 데이터 웨어하우스에도 목적에 따라 적절하게 배열이나 파이썬의 딕셔너리처럼 저장하고 싶을 때 강의의 ARRAY, STRUCT를 사용한다고 생각하시면 될 것 같아요.
- 0
- 2
- 20
질문&답변
슈퍼셋 사용이 처음이라 질문드립니다.
안녕하세요!Superset 자체에도 간단하게 집계하는 기능이 있어서 테이블의 수가 적다면 바로 시각화가 가능하긴 할 거예요. 그러나 여러 테이블을 JOIN해야 하고, 테이블의 부하를 줄이기 위해서는 직접 SQL을 배우셔서 하시는 것이 장기적으론 좋습니다. 어떤 DB를 연결하시나요? 쿼리의 결과를 테이블로 저장하고 그걸 Superset에 연결하면 비용 효율적으로 사용할 수 있어요.제 강의들을 들으시면 SQL로 할 수 있는 대부분을 할 수 있게 되고, 그 쿼리를 토대로 Superset에서 시각화를 하시면 되어요. 시각화 도구는 매번 바뀔 수 있고(Superset, Tableau 등) 대부분 SQL 기능이 있어서 SQL로 하시면 시각화 도구와 상관없이 확장성을 가질 수 있을 거예요
- 0
- 1
- 21
질문&답변
N day 리텐션 쿼리 관련 질문
안녕하세요1번. DISTINCT를 사용한 이유(시작하기 전에) 제가 강의에서 사용한 쿼리가 많아서 듣다가 궁금한 내용에 대해서 쿼리를 붙여주셔도 좋을 것 같아요! 또는 몇 초에 나오는 쿼리라고 말씀해주시면 제가 확인하기 수월합니다(저도 모든 쿼리를 다 기억하는 것이 아니라서 확인하고 이 부분인가? 저 부분인가? 생각하게 되더라구요)말씀하신 것처럼 timestamp 컬럼이 있어서 중복이 있을 확률은 적습니다. 그러나 클라이언트 개발에 따라 다른데 screen_view나 page_view 시리즈와 click이 동시에 발생할 수도 있습니다(약간의 딜레이는 있을 수 있지만 구현에 따라 다름)그리고 저번 질문과 유사한데 지금 단일 테이블에선 중복이 없을 확률이 매우 높지만, 다른 테이블과 JOIN을 할 때 데이터가 많이 늘어날 수 있습니다. 그렇기 때문에 저는 DISTINCT를 항상 사용하면서 중복을 제거하려는 습관이 있다고 생각하시면 됩니다또한 Google Analytics 4, Firebase는 저희가 로깅하지 않아도 발생하는 로그들이 존재합니다. 예를 들어 user_engagement 같은 이벤트가 있습니다. 이런 이벤트를 WHERE 조건에서 제외하는 것도 방법이고, 중복이 있더라도 제거하는 방법도 가능합니다기본적으로 제가 DISTINCT를 쓰는 것은 더 장기적 관점의 습관이라고 보시면 됩니다. DISTINCT를 안써서 JOIN할 때 이슈가 생기는 경험이 많아 중복을 제거하는 것그리고 회사에서 로깅의 이슈로 중복으로 로그가 생기는 경우도 있습니다(개발쪽의 이슈) 그럴 때 개발쪽에서 로그를 수정해달라고 할 수는 있지만, 이미 생긴 로그에 대해서는 삭제가 어려울 수 있습니다. 그런 경우에 데이터쪽에서 쿼리로 중복을 제거하곤 합니다실무에서 JOIN 이슈 + 잘못된 데이터가 있을 경우 => 이를 대비하기 위해 DISTINCT를 쓴다라고 생각해주셔요 2번강의에서 보여드린 diff_of_day, user_cnt는 리텐션 커브를 위한 집계 결과입니다. 330쪽의 쿼리는 "코호트 리텐션"의 형태입니다. 코호트 리텐션은 3-10 강의와 연결됩니다. 그러나 강의에서 보여드린 쿼리에서 first_date만 추가하면 됩니다. 리텐션 커브 -> 코호트 리텐션으로 데이터를 다른 관점으로 보고 있다고 생각하시면 될 것 같아요. 다른 것이 아니라 리텐션 커브를 뽑는 결과 데이터에서 조금만 바꾸면 코호트 리텐션까지 뽑을 수 있습니다(공유해주신 것처럼 first_date 추가) 3번WEEK은 WEEK 단독으로 쓰이진 않고, EXTRACT나 DATE_TRUNC에서 사용할 수 있습니다. 강의에선 EXTRACT와 같이 쓰는 WEEK 의미로 말씀드린거라고 생각해주시면 됩니다! 엄밀히 말하면 강의에서 WEEK 함수라고 했는데 EXTRACT와 함께 쓰이는 WEEK이라고 말씀을 드려야 더 정확했을 것 같네요. 단독 WEEK이 아닌!DATE_TRUNC(date, WEEK(MONDAY)) EXTRACT(WEEK FROM DATE '2025-10-09')
- 0
- 2
- 23
질문&답변
이동평균 계산 시 order by 기본값은 뭔가요?
안녕하세요. 윈도우 함수 내에 ORDER BY는 기본값이 있지 않고, 현재 ORDER BY를 작성하지 않은 경우엔 정렬하지 않은 형태의 데이터에서 프레임을 설정합니다. 지금 문제는데이터가 이미 정렬이 된 상태라서 윈도우 함수 안에 ORDER BY가 없어도 윈도우 함수의 ORDER BY와 같은 결과가 나오게 된 것입니다. 즉, 데이터가 정렬이 되어있기에 이렇게 나온 것입니다(우연히 정렬이 된 데이터였던 것) 확인을 위해 아래 쿼리를 실행해보시면 이해하실 수 있을 것 같아요. 기존 filled_data를 사전에 ORDER BY를 하고 지금 작성하신 쿼리를 비교해보면 결과가 다릅니다. 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 ORDER BY date DESC # 여기에 ORDER BY를 추가해서 데이터 순서를 변경함 ) SELECT *, AVG(number_of_orders) OVER(ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg1, # 위에서 데이터를 정렬한 후 집계한 값 AVG(number_of_orders) OVER(ORDER BY date ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_avg2 # 올바른 답 FROM filled_data 질문해주신 ORDER BY와는 살짝 다르지만, 윈도우 함수에서 프레임을 명시하지 않으면 기본 값은 RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW가 됩니다. 관련 내용은 인프런 AI 인턴이 링크를 걸어준 글을 보시면 도움이 될 것 같아요
- 0
- 2
- 24
질문&답변
윈도우 연습문제 1번 질문
안녕하세요! *의 의미를 본질적으로 이해하시면 좋답니다.COUNT(*) : 모든 Row의 수를 COUNT한다는 의미입니다COUNT(query_date) : query_date에 있는 값의 수를 COUNT한다는 의미입니다.두개의 차이는 NULL을 포함하는지?입니다COUNT(*)은 Row의 수를 세기 때문에 NULL도 포함해서 COUNT를 하고, COUNT(query_date)는 query_date에서 NULL이 아닌 행만 셉니다.지금 데이터에서는 값에 NULL이 없기 때문에 동일하게 나오는거라 보면 됩니다. 데이터가 어떻게 저장되어 있는지를 잘 파악해야 *을 사용할지, 컬럼을 명시할지가 결정됩니다. 그리고 query_date를 사용한 이유는 query_date가 있는 경우를 세고 싶었기 때문이에요. 물론 지금 데이터는 *을 사용해도 괜찮구요. id 같은 값이 있었다면 id를 COUNT할텐데 id가 없는 데이터라 query_date를 COUNT했다고 생각해주시면 되어요 즉, 목적에 따라 다르다입니다. 실무에서 뭘 쓰냐는 결국에 목적에 따라 다릅니다. 내가 어떤 데이터를 보려고 하는지? 그래서 초보자를 위한 BigQuery 입문에서 쿼리를 작성할 때 어떤 것을 구하려고 하는지를 써보라고 템플릿을 드린 거예요. 이게 명시적으로 정리가 되어야 쿼리를 짤 때 판단을 할 수 있어요! 추가로 활용편의 데이터는 단일 테이블이고 NULL이 거의 없습니다. 그래서 강의를 들을 때는 두개 모두 다 상관없이 사용하셔도 됩니다.실무에서 이슈가 되는 경우는 여러 테이블을 JOIN하면서 특정 컬럼에 NULL이 생길 수 있어요. 이럴 때는 데이터의 Row가 늘어난 것처럼 보일 수 있거든요. 이런 경우 *을 쓰면 Row 수만 세서 좀 많아집니다. 그래서 저는 명시적으로 컬럼을 쓰곤 해요. 이번 초보자를 위한 BigQuery 입문의 연습 문제에서 JOIN하고 COUNT하는 문제에서 많이 나타나게 된답니다.
- 0
- 1
- 23
질문&답변
user_id에 NULL이 나오는데 정상인가요?
안녕하세요! 연휴에 열심히 학습하고 계시네요. 답변 드려볼게요 질문1:사진에 보시듯이 user_id 컬럼에 NULL이 들어간 행들이 있는데, 제가 뭔가 잘못한 걸까요? 만약 NULL이 나오는 게 정상이라면 그 이유도 궁금합니다!네 이 부분은 정상입니다. 빅쿼리는 쿼리를 실행할 때, 사람마다 다른 결과를 나올 수 있어요. 현재 쿼리를 집계하거나 하지 않고 SELECT를 했기 때문에 다를 수 있지만 데이터는 동일할 거예요. 질문2:만약 NULL이 나오는 게 정상이라면, 실무에서도 이렇게 id 컬럼에 null이 허용되는지 궁금합니다. 보통 이런 id 값은 primary key로 쓰는 줄 알았어서요..!우선 데이터베이스의 DB의 데이터와 앱 로그에 대한 특성을 이해해야 합니다.아시는 pk 개념은 데이터베이스의 DB에서 나온 개념이고, 로그 데이터는 유저의 흐름 관점이라 다를 수 있습니다우리가 어떤 서비스에 접속할 때(웹이나 앱이나) 로그인을 하지 않은 경우엔 앱에서 user_id를 알 수 없습니다. 그래서 user_id가 그 시점에는 NULL입니다. 지금 NULL은 그런 케이스라고 생각하시면 되고, 파라미터를 잘 보시면 welcome 페이지에 접근한 케이스라서(환영 페이지 = 아직 로그인을 안함) 그렇게 나옵니다이 부분은 1-8. 퍼널의 정의, 종류, 집계 방법 강의에서 다루고 있어요. 유저를 어떤 기준으로 집계할 것이냐 관점으로 나옵니다. 이 부분 보시면 이해가 되실 것 같습니다! 질문3:연습문제 뒤에 추가로 COUNT 출력해보는 것도 결과(cnt)가 다른데, 이것도 정상인지 확인부탁드립니다. 혹시 카일스쿨님이 강의 찍으실 때 쓰신 데이터셋과 변동사항이 있나요?데이터는 달라지지 않았습니다. 쿼리를 보니까, 저는 영상에서 DISTINCT를 사용했고, a01042338414님은 DISTINCT가 없이 집계를 해서 이벤트 발생 횟수를 COUNT한 것입니다. DISTINCT를 넣으시면 같게 나올 거예요.12. 1-4. ARRAY, STRUCT 연습 문제(4번) 9분 33초(사진)
- 0
- 2
- 26
질문&답변
espanso 설치 완료 후 프로그램 실행 문제
안녕하세요! 지금 사용하시는 프로그램 대신 PowerShell을 실행해서 espanso를 써보시면 되실까요?명령 프롬프트 기본 프로그램보다 PowerShell이 환경 설정을 잡아주는 경우를 봐서 이거 시도해보고 안되시면 말씀해주셔요! 저도 찾아볼게요
- 0
- 2
- 32
질문&답변
3-13 리텐션 과제 제출
재현님 고생하셨습니다! 이 문제가 정말 난이도가 있는 문제긴 합니다. 실무에서도 고민을 많이 해야하는 부분이고, 이런 과정을 하신 것이 실무를 간접적으로 경험한 것이라고 생각합니다 이 문제가 최종 과제와 연결되는 부분이라, 피드백을 토대로 고민을 해보시는 것을 추천합니다 피드백1, 4번의 경우 쿼리를 작성해보는 것을 목표로 한 것이고 잘 작성하셨습니다. 이걸 나아가서 쿼리 작성으로 끝이 아니라 더 자세히 해석하고, 가설을 만드는 것도 해보시는 것을 추천해요3번3번은 데이터를 본 후에 -> 해당 데이터에서 가설을 떠올리는 것이 필요합니다. 어떤 사람들이 많이 계속 사용할까?여기서 검색을 1번이라도 한 사람이 리텐션이 높을까? -> 검색 1번을 한 사람들의 리텐션 비율과 전체적인 비율과 비교이렇게 가설을 만들고, 데이터를 구체적으로 뽑고, 검색 1번을 한 사람과 검색 2번을 한 사람의 차이는? 또는 어떤 이벤트를 하면 사람들이 더 많이 들어온다! 이런 것을 발견하는 것이 중요합니다2번2번은 Retain User로 생각하면 어려워서, WAU를 New, Current, Resurrected, Dormant로 구분해보는 것을 추천합니다작성해주신 것처럼 각각을 정의하고, Dormant에서+4라고 했는데 그럼 왜 +4인가?라고 누군가 물어보면 근거를 데이터로 제시할 수 있어야 합니다Resurrected는 왜 5주일까요?Current는 왜 직전 3주일까요?이런 근거를 정할 때 정답이 있는 것이 아니라, 데이터를 보면서 판단해야 합니다주차별로 New, Current, Resurrected, Dormant 인원이 계속 달라질텐데 이걸 구해보셔요1주차에 New였던 유저가 2주차엔 Current로 상태가 변할 수도 있습니다주차별 New, Current, Resurrected, Dormant를 구하면 신규 유저가 많이 들어오는지, 현재 유저가 들어오는지 등을 토대로 어떤 사람들을 집중으로 Action을 할 지 떠올릴 수 있답니다분석이 제대로 안된 것 같으시다면 Action Item을 구체적으로 내지 않아서 그럴 수 있습니다. 쿼리를 짜고 데이터를 간단하게 보는 것은 분석의 레벨이 얕고, 나온 데이터를 보면서 또 가설을 생각해보고, 그걸 데이터로 확인해보고, Action Item을 떠올리는 것이 분석이라고 생각하시면 됩니다 최종 과제도 있으니 이 부분 참고해서 봐보셔요. 최종 과제에서 목표는 단순히 쿼리 작성이 목표가 아니라, 가설을 잡아서 해결하는 것이 핵심이에요. 고생하셨습니다!
- 0
- 2
- 46
질문&답변
Syntax에러
안녕하세요. 첫번째 이미지에서는 SELECT 절에 컬럼이 없어서 오류가 발생하고 있네요.SELECT와 FROM 사이에 *을 넣어주면 실행 됩니다 두번째 이미지에는 지금 빨간색으로 NULL이란 이상한 문자가 들어가서 오류가 발생하고 있습니다. 이 문자를 삭제하면 됩니다!
- 0
- 2
- 40