inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

묻고 답해요

172만명의 커뮤니티!! 함께 토론해봐요.

오타 제보입니다.

미해결

김영한의 실전 자바 - 고급 1편, 멀티스레드와 동시성

수강하고 있는 좋은 강의의 내용이 명확히 전달되기를 바라는 마음으로 오타 제보 드립니다. 생산자 소비자 문제1.pdf [오타] 소비자 스레드는 데이터를 소비자 고, [변경] 소비자 스레드는 데이터를 소비하고,

  • java
  • 객체지향
  • 동시성
  • multithread
  • thread
꾸준히쌓자 댓글 2 좋아요 0 조회수 151

제네릭 코드에서 new 키워드를 사용할 수 없다면 불변 객체를 어떻게 활용할 수 있나요?

미해결

김영한의 실전 자바 - 중급 2편

불변 객체는 내부 필드에 변경이 생길 경우 새로운 객체를 반환해줘야 한다고 배웠습니다. 제네릭 타입은 타입 소거 문제 때문에 new 키워드를 사용할 수 없는데... 이 경우 제네릭과 불변 객체는 공존할 수 없는 건가요? 아래 코드와 같이 실습을 해봤는데 주석 처리한 부분을 어떻게 해결해야 할지 잘 모르겠습니다 ㅠㅠ public class Box<T extends Animal> { private final T value; public Box(T value) { this.value = value; } public T get() { return value; } public Box<T> withName(String name) { //이 부분을 어떻게 처리해야할까요..? } } public class Animal { private final String name; private final int size; public Animal(String name, int size) { this.name = name; this.size = size; } public Animal withName(String name) { return new Animal(name, size); } public class Dog extends Animal { public Dog(String name, int size) { super(name, size); } @Override public Dog withName(String name) { return new Dog(name, getSize()); } }

  • java
  • 객체지향
  • 제네릭
  • 불변
싱숭생숭 댓글 1 좋아요 0 조회수 207

포괄적 에러 핸들링 error.tsx이 정상 작동 하지 않습니다 (05:30)

해결됨

한 입 크기로 잘라먹는 Next.js

안녕하세요 서버는 종료한 상태에서 강의대로 (with-searchbar)/error.tsx 파일을 만들고 새로고침을 하면 error.tsx에서 작성한 페이지가 나오지 않습니다. error.tsx 인덱스 페이지 아래 사진처럼 error.tsx페이지가 아닌 핸들링되지 않은 런타임 에러가 발생해버립니다.. 혹시 searchParams를 Promise객체로 타입정의 한것처럼 뭔가 사용방법이 바뀐걸까요..?

  • react
  • typescript
  • next.js
  • error.tsx
김동환 댓글 2 좋아요 3 조회수 474

Controller에서 Repository 참조

미해결

실전! 스프링 데이터 JPA

학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 안녕하세요. 잘 보고 있습니다. 컨트롤러에서 Repository에 바로 의존성이 있는 방식으로 사용하는 예제를 알려주셨는데 간단한 예시를 들어주시느라 사용하신 패턴이신가요? 아니면 어차피 페이징 기능은 레포지토리 단의 간단한 메서드로 충분히 수행되므로 서비스 레이어를 통한 매핑이 불필요해서 그러신건가요??

  • java
  • spring
  • spring-boot
  • jpa
김해찬 댓글 2 좋아요 0 조회수 144

fetchjoin 미적용 쿼리

미해결

실전! Querydsl

@PersistenceUnit EntityManagerFactory emf; @Test public void fetchJoinNo() { em.flush(); em.clear(); Member findMember = queryFactory.selectFrom(member).where(member.name.eq("kim")).fetchOne(); boolean loaded = emf.getPersistenceUnitUtil().isLoaded(findMember.getCart()); assertThat(loaded).as("패치조인미적용").isFalse(); } // select // m1_0.member_id, // m1_0.city, // m1_0.street, // m1_0.zipcode, // m1_0.cart_id, // m1_0.member_login_id, // m1_0.member_login_pw, // m1_0.name // from // member m1_0 // where // m1_0.name=? // -> 분명히 fetch join 미적용인데 select 절에 연관 entity 가 같이 조회되는 이유를 모르겠습니다. 현재 Cart 엔티티는 member 와 @OneToOne 관계이고 @FetchJoin.LAZY 로 설정되어 있습니다.

  • java
  • jpa
수빈 댓글 2 좋아요 0 조회수 176

Next.js SSR 방식에 대해 질문 드립니다.

해결됨

한 입 크기로 잘라먹는 Next.js

안녕하세요 강의 잘 듣고 있습니다. SSR 의 동작방식에 대해 문의 드립니다. 1) 프로젝트에 초기 접속할때는 '/' 페이지에 대한 HTML 반환 후 js bundle 반환 => 하이드레이션 2) '/search' 로 이동하면 '/search' 페이지에 대한 HTML 반환 후 캐싱된 js bundle 과 결합하여 하이드레이션 저는 대충 위 과정으로 이해하고 있었는데, 페이지에 따라 js bundle을 추가로 요청하는 경우도 있다고 해서 헷갈리는 것 같습니다. 초기 접속과 이후 새로운 페이지를 요청할때 HTML 응답과 js bundle 응답이 어떤식으로 동작하는지 설명 부탁 드립니다!

  • next.js
  • ssr
Byoungmin Kang 댓글 2 좋아요 0 조회수 230

skeleton UI 적용 시점

해결됨

한 입 크기로 잘라먹는 Next.js

안녕하세요 현재 6.4)스켈레톤 UI 적용하기 강의를 듣고나서 궁금한점이 있어 질문 남깁니다. 서버쪽 데이터요청이 오래 걸리는 경우 Suspense를 통해 Skeleton UI를 보여주고 이후 데이터가 적용 된 컴포넌트를 보여주는거로 알고 있습니다. 그래서 사용자경험이 조금 오를 것 같긴한데, 만약 데이터 요청이 빠른 경우(0.5초만에 데이터처리가 이뤄진 경우)에는 오히려 UX 관점에서 불편하지 않을까 싶어서 이럴땐 어떻게 처리하는게 좋을 지 질문 남깁니다! 예시) 책 검색 -> 책 리스트의 skeleton UI 가 잠깐 보였다가(0.5초 등장) -> 책 리스트 나타남 (이와 같은 과정이 이뤄지면 오히려 사용자 경험이 떨어지지 않을까 싶어 궁금합니다)

  • react
  • typescript
  • next.js
leekyungmin 댓글 1 좋아요 1 조회수 327

강의 연장 여부 질문

해결됨

SW 개발자를 위한 성능 좋은 SQL 쿼리 작성법

안녕하세요, 김정선 강사님. 강의 잘 듣고 있습니다. 다름이 아니라, 개인적인 사정으로 인해 강의를 기간 내에 모두 수강하지 못하였는데, 혹시 강의 연장이 가능한지 여쭙고자 합니다. 부디 확인 부탁드리며, 답변 주시면 감사하겠습니다!! 감사합니다.

  • sql
  • dbms/rdbms
퍼시스 댓글 2 좋아요 0 조회수 143

인증 코드를 통해 발급 받은 토큰의 관리

미해결

스프링 시큐리티 OAuth2

안녕하세요 강사님 OAuth2 로그인을 구현하고 회원 탈퇴를 위해 구글과 카카오의 unlink API를 호출하려는데, 소셜 로그인 과정을 시큐리티가 자동으로 처리해주고 있어서 API 호출에 필요한 토큰이 관리되고 있지 않은 상황입니다. 이럴 때 어떤 방식으로 토큰을 받아야 하는지 궁금합니다. 제가 생각해본 방법은 다음 두가지가 있습니다. 첫 번째 방법 : 인증 코드를 직접 요청하고, 반환 받은 인증 코드로 토큰 또한 직접 요청 두 번째 방법 : 설정해둔 리다이렉트 URI에 대한 처리를 직접 구현 후, 인증 코드를 받고, 해당 인증 코드로 토큰을 직접 요청 혹시 이중에 맞는 방법이 있는지, 아니면 시큐리티의 자연스러운 흐름안에서 토큰을 받을 방법이 있을까요? 보통 어떤식으로 토큰 값을 받는지 궁금합니다!

  • java
  • spring
  • spring-boot
  • oauth
댓글 1 좋아요 0 조회수 213

pojo 에 setter 가 없는 경우가 있을까요?

해결됨

실전 jOOQ! Type Safe SQL with Java

안녕하세요 강사님. jooq 강의 잘 듣고 있습니다. 현재 update 부분 강의를 들으면서 실습해보고 있는데 Actor 에 setter 메소드들이 없어서 dao 를 통한 update를 하는데 다소 어려움이 생겼습니다. insert 의 경우는 생성자에 데이터를 넣어서 잘 넘어갔는데, update 에서는 setter 가 없으니까, insert 한 값을 Actor 객체로 반환 받아서 그 객체에 있는 setter 를 이용해 update 하는 방식이 불가능하다 보니 "setter 는 어디로 갔는가?" 생각이 들더라구요. 실습중인 jooq 버전은 3.19.5 이고, 아래는 Actor pojo 파일 구조 입니다.

  • java
  • sql
  • spring-boot
  • jooq
  • dsl
창랑 댓글 1 좋아요 1 조회수 216

2-16 ssg 구현중 에러입니다.

해결됨

한 입 크기로 잘라먹는 Next.js

안녕하세요 강사님, 강의를 듣는 중 문제가 발생해 글 남깁니다. book/id 상세페이지에서 SSG getStaticPaths를 적용중인데, id를 인식을 못해 에러가 발생합니다. Error: A required parameter (id) was not provided as an array received string in getStaticPaths for /book/[[...id]] 강의에 의하면, books/1 은 보여야 하는데 페이지가 보이지 않네요 오타인 것 같아 강사님 깃헙 코드도 복사해서 붙여봤는데 에러가 납니다 혹시 다른 문제가 있을까요? 에러 메세지에는 id가 제공이 안된다고 하는데, 제가 보기에는 staticProps에 맞게 변경한거 같은데, 왜 에러가 날까요??

  • react
  • typescript
  • next.js
나를응원해 댓글 2 좋아요 0 조회수 124

한국어 더빙이 안되는것 같네요~

해결됨

[인프런 X VMware Tanzu] Spring Boot 밋업 with Josh Long

한국어 더빙이 안되는것 같은데요~ 다른 언어는 다 되는데 한국어를 선택하면 영어로 나오네요~

  • java
  • spring
  • spring-boot
이종석 댓글 1 좋아요 0 조회수 199

ThreadPool 방식 질문드립니다

해결됨

FastAPI 완벽 가이드

강의 정말 도움 많이 되었습니다!! 강의 내용 중에 동시성인지 병렬성인지 헷갈리는게 있어 질문드립니다..! 7:35에 일반 def 함수 라우터로 작성한 ThreadPool(병렬) 방식은 매번 요청시 ThreadPool에서 유휴 Tread를 찾아 동작하고 i/o wait가 발생할때 context switch를 해가면서 작업하는 것으로 이해했는데...이게 맞다면..! 완벽한 병렬성이 아니라 동시에 작업하는 것 처럼 보이는 동시성으로 동작하는 건가요?

  • python
  • sql
  • sqlalchemy
  • FastAPI
kristin 댓글 2 좋아요 0 조회수 229

계층형 쿼리 용어 정리 및 문법 강의 - 강의 오타인 거 같습니다

미해결

실습으로 손에 잡히는 SQLD(2과목)

안녕하세요 SQLD 준비하고 있는 전진호 학생입니다. 강의 2:47에서 'PRIOR PK = FK' PK (부모)-> FK(자식) 순방향 전개 'PRIOR FK = PK' FK (자식)-> PK(부모) 역방향 전개 이렇게 나와야 하는 슬라이드에서 'PRIOR PK = FK' PK (부모)-> FK(자식) 순방향 전개 'PRIOR FK = PK' FK (자식)-> FK(부모) 역방향 전개 FK -> PK가 FK -> FK로 바뀐 거 같습니다. 감사합니다. 전진호 드림.

  • sql
  • oracle
  • mssql
  • SQLD
전진호 댓글 1 좋아요 1 조회수 167

[빠짝스터디 3주차 과제] 리텐션 연습문제

해결됨

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

1) Weekly Retention을 구하는 쿼리를 바닥부터 스스로 작성해보세요 WITH base AS ( SELECT DISTINCT user_id, user_pseudo_id, event_name, DATETIME(TIMESTAMP_MICROS(event_timestamp), "Asia/Seoul") AS event_datetime, DATE(DATETIME(TIMESTAMP_MICROS(event_timestamp), "Asia/Seoul")) AS event_date FROM `advanced.app_logs` ), first_week_and_diff AS ( SELECT *, DATE_DIFF(event_week, first_week, WEEK) AS diff_of_week FROM ( SELECT DISTINCT user_pseudo_id, DATE_TRUNC(MIN(event_date) OVER(PARTITION BY user_pseudo_id), WEEK(MONDAY)) AS first_week, DATE_TRUNC(event_date, WEEK(MONDAY)) AS event_week FROM base ) ) SELECT diff_of_week, COUNT(DISTINCT user_pseudo_id) AS user_cnt, ROUND(SAFE_DIVIDE((COUNT(DISTINCT user_pseudo_id)), (FIRST_VALUE(COUNT(DISTINCT user_pseudo_id)) OVER(ORDER BY diff_of_week))), 3) AS retention FROM first_week_and_diff GROUP BY diff_of_week ORDER BY diff_of_week 2) Retain User를 New+Current+Resurrected+DormantUser로 나누는 쿼리를 작성해보세요. 유저 구분 기준은 제품이나 서비스에 따라 다르겠지만 applogs 데이터는 주단위로 했을때 총 24주치 데이터가 있었고, 유저별로 평균 구매 주기와 방문 횟수를 구해보았을 때 6주를 기준으로 유저를 구분하면 될 것이라 생각함. New : 첫 방문한 신규 유저 Current : 방문 횟수 2회 이상이면서 6주 이내 재 방문 이력 있는 유저 Resurrected : 방문 횟수 2회 이상 & 직전 방문 경과 7주 이상이면서 6주 이내 재방문 이력 있는 유저 Dormant : 직전 방문 경과 7주 이상이면서 6주 이내 재방문 없는 유저 (사실 이렇게 나누는게 맞는지 모르겠지만, 나름의 논리적인 기준을 찾아보려고 노력하였음. 😫 과제 기한 연장에도 개인적인 사정으로 시간이 부족하여 깊이 탐구하지 못했고, 쿼리 작성을 완성하지 못했습니다 😩 추후에 완성하면 보완하도록 하겠습니다. ) 3) 주어진 데이터에서 어떤 사람들이 리텐션이 그나마 높을까요? 찾아보세요 미완성으로 추후에 완성하면 보완하겠습니다 ! 4) Core Event를 “click_payment” 라고 설정하고 Weekly Retention을 구해주세요 WITH base AS ( SELECT DISTINCT user_id, user_pseudo_id, event_name, DATETIME(TIMESTAMP_MICROS(event_timestamp), "Asia/Seoul") AS event_datetime, DATE(DATETIME(TIMESTAMP_MICROS(event_timestamp), "Asia/Seoul")) AS event_date FROM `advanced.app_logs` ), first_week_and_diff AS ( SELECT *, DATE_DIFF(event_week, first_week, WEEK) AS diff_of_week FROM ( SELECT DISTINCT user_pseudo_id, DATE_TRUNC(MIN(event_date) OVER(PARTITION BY user_pseudo_id), WEEK(MONDAY)) AS first_week, DATE_TRUNC(event_date, WEEK(MONDAY)) AS event_week FROM base ) ) SELECT diff_of_week, COUNT(DISTINCT user_pseudo_id) AS user_cnt, ROUND(SAFE_DIVIDE((COUNT(DISTINCT user_pseudo_id)), (FIRST_VALUE(COUNT(DISTINCT user_pseudo_id)) OVER(ORDER BY diff_of_week))), 3) AS retention FROM first_week_and_diff GROUP BY diff_of_week ORDER BY diff_of_week

  • sql
  • Google-Analytics
  • firebase
  • google-sheets
  • bigquery
Sunny 댓글 1 좋아요 0 조회수 141

- FIRST_VALUE, LAST_VALUE

미해결

실습으로 손에 잡히는 SQLD(2과목)

WITH Sales AS ( SELECT 1 AS sale_id, DATE '2023-01-01' AS sale_date, 101 AS employee_id, 500 AS amount FROM dual UNION ALL SELECT 2 AS sale_id, DATE '2023-01-02' AS sale_date, 102 AS employee_id, 700 AS amount FROM dual UNION ALL SELECT 3 AS sale_id, DATE '2023-01-03' AS sale_date, 101 AS employee_id, 300 AS amount FROM dual UNION ALL SELECT 4 AS sale_id, DATE '2023-01-04' AS sale_date, 103 AS employee_id, 900 AS amount FROM dual UNION ALL SELECT 5 AS sale_id, DATE '2023-01-05' AS sale_date, 101 AS employee_id, 400 AS amount FROM dual UNION ALL SELECT 6 AS sale_id, DATE '2023-01-06' AS sale_date, 104 AS employee_id, 600 AS amount FROM dual UNION ALL SELECT 7 AS sale_id, DATE '2023-01-07' AS sale_date, 105 AS employee_id, 800 AS amount FROM dual UNION ALL SELECT 8 AS sale_id, DATE '2023-01-08' AS sale_date, 101 AS employee_id, 350 AS amount FROM dual UNION ALL SELECT 9 AS sale_id, DATE '2023-01-09' AS sale_date, 102 AS employee_id, 450 AS amount FROM dual UNION ALL SELECT 10 AS sale_id, DATE '2023-01-10' AS sale_date, 103 AS employee_id, 750 AS amount FROM dual UNION ALL SELECT 11 AS sale_id, DATE '2023-01-11' AS sale_date, 101 AS employee_id, 250 AS amount FROM dual UNION ALL SELECT 12 AS sale_id, DATE '2023-01-12' AS sale_date, 104 AS employee_id, 650 AS amount FROM dual UNION ALL SELECT 13 AS sale_id, DATE '2023-01-13' AS sale_date, 105 AS employee_id, 850 AS amount FROM dual UNION ALL SELECT 14 AS sale_id, DATE '2023-01-14' AS sale_date, 101 AS employee_id, 450 AS amount FROM dual UNION ALL SELECT 15 AS sale_id, DATE '2023-01-15' AS sale_date, 102 AS employee_id, 550 AS amount FROM dual UNION ALL SELECT 16 AS sale_id, DATE '2023-01-16' AS sale_date, 103 AS employee_id, 950 AS amount FROM dual UNION ALL SELECT 17 AS sale_id, DATE '2023-01-17' AS sale_date, 104 AS employee_id, 700 AS amount FROM dual UNION ALL SELECT 18 AS sale_id, DATE '2023-01-18' AS sale_date, 105 AS employee_id, 900 AS amount FROM dual UNION ALL SELECT 19 AS sale_id, DATE '2023-01-19' AS sale_date, 101 AS employee_id, 500 AS amount FROM dual UNION ALL SELECT 20 AS sale_id, DATE '2023-01-20' AS sale_date, 102 AS employee_id, 600 AS amount FROM dual ) SELECT SALE_ID, TO_CHAR(SALE_DATE, 'YYYY-MM-DD') AS sale_date, employee_id, amount, FIRST_VALUE(amount) OVER (PARTITION BY employee_id ORDER BY sale_date) AS "FIRST_VALUE" FROM ( SELECT SALE_ID, SALE_DATE, employee_id, amount, ROW_NUMBER() OVER (PARTITION BY employee_id ORDER BY sale_date) AS rn FROM Sales ) WHERE rn = 1; 안녕하세요 SQLD 준비하면서 강의 듣고 있는 전진호 학생입니다. 이렇게 SUBQUERY에서 ROW-NUMBER를 이용해서 하지 않고, PARTITION BY 의 첫번째 값만 뽑아낼 수 있는 좀 더 쉬운 방법이 있을까요? 감사합니다.

  • sql
  • oracle
  • mssql
  • SQLD
전진호 댓글 0 좋아요 0 조회수 131

[인프런 빅쿼리 빠짝스터디 3주차] 리텐션 과제

해결됨

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

1번 문제 WITH -- 1단계: 필수 데이터만 추출하기 base_events AS ( SELECT user_pseudo_id, DATE(TIMESTAMP_MICROS(event_timestamp), "Asia/Seoul") AS event_date FROM advanced.app_logs ), -- 2단계: 사용자별 첫 방문 주차와 각 활동 주차 구하기 user_weeks AS ( SELECT DISTINCT -- 중복 제거 user_pseudo_id, -- 사용자별 첫 방문 주차 (월요일 기준) DATE_TRUNC(MIN(event_date) OVER(PARTITION BY user_pseudo_id), WEEK(MONDAY)) AS first_week, -- 실제 방문한 주차 (월요일 기준) DATE_TRUNC(event_date, WEEK(MONDAY)) AS visit_week FROM base_events ), -- 3단계: 첫 방문 이후 몇 주차인지 계산하기 week_numbers AS ( SELECT user_pseudo_id, -- 첫 방문 이후 경과된 주차 계산 DATE_DIFF(visit_week, first_week, WEEK) AS week_number FROM user_weeks -- 최대 12주까지만 분석 WHERE DATE_DIFF(visit_week, first_week, WEEK) <= 12 ), -- 4단계: 주차별 총 사용자 수 계산하기 weekly_users AS ( SELECT week_number, COUNT(DISTINCT user_pseudo_id) AS user_count FROM week_numbers GROUP BY week_number ) -- 5단계: 최종 리텐션 계산하기 SELECT week_number, user_count as active_users, FIRST_VALUE(user_count) OVER(ORDER BY week_number) as first_week_users, ROUND(100.0 * user_count / FIRST_VALUE(user_count) OVER(ORDER BY week_number), 2) as retention_rate FROM weekly_users ORDER BY week_number; 2번 문제 WITH -- 1단계: 사용자별 주차 데이터 준비 user_weeks AS ( SELECT DISTINCT user_pseudo_id, -- 첫 방문 주차 DATE_TRUNC(MIN(DATE(TIMESTAMP_MICROS(event_timestamp), "Asia/Seoul")) OVER(PARTITION BY user_pseudo_id), WEEK(MONDAY)) AS first_week, -- 활동 주차 DATE_TRUNC(DATE(TIMESTAMP_MICROS(event_timestamp), "Asia/Seoul"), WEEK(MONDAY)) AS event_week FROM advanced.app_logs ), -- 2단계: 사용자 상태 확인 user_status AS ( SELECT user_pseudo_id, event_week, first_week, -- 이전 방문 주차 LAG(event_week) OVER(PARTITION BY user_pseudo_id ORDER BY event_week) AS prev_week FROM user_weeks ), -- 3단계: 상태 분류 weekly_status AS ( SELECT event_week, user_pseudo_id, CASE WHEN event_week = first_week THEN 'New' WHEN DATE_DIFF(event_week, prev_week, WEEK) = 1 THEN 'Current' WHEN DATE_DIFF(event_week, prev_week, WEEK) > 1 THEN 'Resurrected' END as user_type FROM user_status ), -- 4단계: 각 주차별 전체 유저 수 total_users AS ( SELECT fwd.event_week, COUNT(DISTINCT user_pseudo_id) AS total_user_count FROM user_status CROSS JOIN (SELECT DISTINCT event_week FROM user_weeks) AS fwd WHERE first_week <= fwd.event_week GROUP BY event_week ), -- 5단계: 주차별 활성 유저 수 계산 active_users AS ( SELECT event_week, COUNTIF(user_type = 'New') AS new_users, COUNTIF(user_type = 'Current') AS current_users, COUNTIF(user_type = 'Resurrected') AS resurrected_users, COUNT(DISTINCT user_pseudo_id) AS retain_users FROM weekly_status GROUP BY event_week ) -- 6단계: 최종 결과 SELECT FORMAT_DATE('%Y-%m-%d', a.event_week) as week_start, new_users, current_users, resurrected_users, (t.total_user_count - a.retain_users) as dormant_users, ROUND(100.0 * current_users / NULLIF(LAG(new_users) OVER(ORDER BY a.event_week), 0), 1) as retention_rate, retain_users as active_users, t.total_user_count as total_users FROM active_users a JOIN total_users t ON a.event_week = t.event_week ORDER BY a.event_week; 3번 문제 WITH -- 1단계: 기본 데이터 준비 user_weeks AS ( SELECT DISTINCT user_pseudo_id, DATE_TRUNC(MIN(DATE(TIMESTAMP_MICROS(event_timestamp), "Asia/Seoul")) OVER(PARTITION BY user_pseudo_id), WEEK(MONDAY)) AS first_week, DATE_TRUNC(DATE(TIMESTAMP_MICROS(event_timestamp), "Asia/Seoul"), WEEK(MONDAY)) AS event_week FROM advanced.app_logs ), -- 2단계: 사용자별 방문 주차 수 계산 user_visit_frequency AS ( SELECT user_pseudo_id, COUNT(DISTINCT event_week) as total_visit_weeks, DATE_DIFF(MAX(event_week), MIN(event_week), WEEK) + 1 as weeks_since_first, MIN(event_week) as first_visit_week FROM user_weeks GROUP BY user_pseudo_id ), -- 3단계: 사용자별 리텐션 점수 계산 user_retention_score AS ( SELECT user_pseudo_id, total_visit_weeks, weeks_since_first, ROUND(100.0 * total_visit_weeks / weeks_since_first, 2) as visit_rate, FORMAT_DATE('%Y-%m', first_visit_week) as cohort_month FROM user_visit_frequency WHERE weeks_since_first >= 4 -- 최소 4주 이상 경과된 사용자만 ), -- 4단계: 사용자 행동 데이터 분석 user_behavior AS ( SELECT r.user_pseudo_id, r.visit_rate, r.cohort_month, COUNT(DISTINCT DATE(TIMESTAMP_MICROS(l.event_timestamp), "Asia/Seoul")) as active_days, COUNT(DISTINCT l.event_timestamp) as total_events, COUNT(DISTINCT l.event_name) as unique_event_types FROM user_retention_score r JOIN advanced.app_logs l ON r.user_pseudo_id = l.user_pseudo_id GROUP BY r.user_pseudo_id, r.visit_rate, r.cohort_month ), -- 5단계: 리텐션 세그먼트별 행동 패턴 분석 retention_segments AS ( SELECT cohort_month, CASE WHEN visit_rate >= 75 THEN 'Very High (75%+)' WHEN visit_rate >= 50 THEN 'High (50-74%)' WHEN visit_rate >= 25 THEN 'Medium (25-49%)' ELSE 'Low (<25%)' END as retention_segment, COUNT(DISTINCT user_pseudo_id) as user_count, ROUND(AVG(visit_rate), 2) as avg_retention_rate, ROUND(AVG(active_days), 1) as avg_active_days, ROUND(AVG(total_events), 1) as avg_total_events, ROUND(AVG(unique_event_types), 1) as avg_unique_events FROM user_behavior GROUP BY cohort_month, CASE WHEN visit_rate >= 75 THEN 'Very High (75%+)' WHEN visit_rate >= 50 THEN 'High (50-74%)' WHEN visit_rate >= 25 THEN 'Medium (25-49%)' ELSE 'Low (<25%)' END ) -- 최종 결과 SELECT cohort_month, retention_segment, user_count, avg_retention_rate, avg_active_days, avg_total_events, avg_unique_events, ROUND(100.0 * user_count / SUM(user_count) OVER (PARTITION BY cohort_month), 2) as segment_percentage FROM retention_segments ORDER BY cohort_month, CASE retention_segment WHEN 'Very High (75%+)' THEN 1 WHEN 'High (50-74%)' THEN 2 WHEN 'Medium (25-49%)' THEN 3 WHEN 'Low (<25%)' THEN 4 END; 4번 WITH -- 1단계: 결제 이벤트 기본 데이터 payment_base AS ( SELECT DISTINCT user_pseudo_id, DATE(TIMESTAMP_MICROS(event_timestamp), "Asia/Seoul") AS event_date FROM advanced.app_logs WHERE event_name = "click_payment" ), -- 2단계: 사용자별 첫 결제일과 주차 계산 user_weeks AS ( SELECT user_pseudo_id, -- 첫 결제 주차 DATE_TRUNC(MIN(event_date) OVER(PARTITION BY user_pseudo_id), WEEK(MONDAY)) AS first_week, -- 실제 결제 주차 DATE_TRUNC(event_date, WEEK(MONDAY)) AS event_week FROM payment_base ), -- 3단계: 주차별 상태 계산 week_status AS ( SELECT user_pseudo_id, event_week, first_week, -- 첫 주차와의 차이 DATE_DIFF(event_week, first_week, WEEK) AS week_number FROM user_weeks WHERE DATE_DIFF(event_week, first_week, WEEK) <= 12 -- 최대 12주까지만 분석 ), -- 4단계: 주차별 활성 사용자 수 계산 weekly_users AS ( SELECT week_number, COUNT(DISTINCT user_pseudo_id) AS active_users FROM week_status GROUP BY week_number ), -- 5단계: 첫 주 사용자 수 (코호트 크기) 구하기 first_week_users AS ( SELECT COUNT(DISTINCT user_pseudo_id) AS cohort_size FROM week_status WHERE week_number = 0 ) -- 최종 결과 SELECT week_number as week, active_users, cohort_size, ROUND(100.0 * active_users / cohort_size, 2) as retention_rate FROM weekly_users CROSS JOIN first_week_users ORDER BY week_number; 서비스 성장세 총 사용자: 52,823명까지 증가 8월부터 12월까지 꾸준한 성장 10월에 가장 높은 신규 유저 유입 (4,048명) 리텐션 개선 전체 리텐션: 8월 2.6% → 1월 47.9%로 큰 폭 개선 12월부터 40% 이상의 안정적인 리텐션 유지 재방문 사용자 비중이 지속적으로 증가 개선 필요점 결제 리텐션이 매우 낮음 (1% 수준) 신규 사용자 유입이 감소 추세 휴면 사용자가 지속적으로 증가

  • sql
  • Google-Analytics
  • firebase
  • google-sheets
  • bigquery
김세현 댓글 1 좋아요 0 조회수 111

바짝 스터디 3주차 과제 제출

해결됨

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

연습문제 1번 select *, TRUNC(user_count / first_count, 3) AS ratio from ( select *, first_value(user_count) over(order by week_diff asc) as first_count from ( select week_diff, count(*) as user_count from ( select *, date_diff(datetime_week, first_week, week) as week_diff from ( select distinct event_date, user_pseudo_id, platform, datetime_week, -- event_name, first_value(datetime_week) over (partition by user_pseudo_id order by datetime_week asc) as first_week from ( select * except(firebase_screen,event_name), DATETIME_TRUNC(CAST(event_date AS DATE), WEEK) AS datetime_week, concat(firebase_screen,'_',event_name) as event_name from ( select * except(event_param), max(if(event_param.key = 'firebase_screen',event_param.value.string_value , null)) as firebase_screen from ( select event_date, event_timestamp, user_pseudo_id, platform, event_name, event_param from `advanced.app_logs` cross join unnest(event_params) as event_param where event_date >= '2022-08-01' and event_date <= '2022-08-30' ) group by all ) ) ) ) group by week_diff ) ) order by week_diff ; 연습문제2 현재 시간에서 마지막 활동이 2주 이상 경과면 이탈 마지막 활동이 현재 시간에서 1주 이내 인데 이전 활동과 갭이 2주이상이면 복귀 마지막 action이 현재시간에서 1주내이고 이전 액션이 없다면 new 나머진 active select user_pseudo_id, case when DATETIME_DIFF(now, datetime_week, WEEK) >= 2 then 'dormant' when DATETIME_DIFF(datetime_week, last_visit_week, WEEK) < 2 and DATETIME_DIFF(now, datetime_week, WEEK) < 2 then 'active' when DATETIME_DIFF(datetime_week, last_visit_week, WEEK) >= 2 and DATETIME_DIFF(now, datetime_week, WEEK) < 2 then 'resurrected' when DATETIME_DIFF(now, datetime_week, WEEK) < 2 and last_visit_week is null then 'new' else null end as status from ( select *, rank() over (partition by user_pseudo_id order by event_timestamp desc) as rank from ( select distinct event_date, user_pseudo_id, platform, datetime_week, event_timestamp, -- event_name, -- first_value(datetime_week) over (partition by user_pseudo_id order by datetime_week asc) as first_week lag(datetime_week) over(partition by user_pseudo_id order by event_timestamp) as last_visit_week, CAST('2022-08-31 00:00:00' AS DATETIME) as now, from ( select * except(firebase_screen,event_name), DATETIME_TRUNC(CAST(event_date AS DATE), WEEK) AS datetime_week, concat(firebase_screen,'_',event_name) as event_name from ( select * except(event_param), max(if(event_param.key = 'firebase_screen',event_param.value.string_value , null)) as firebase_screen from ( select event_date, event_timestamp, user_pseudo_id, platform, event_name, event_param from `advanced.app_logs` cross join unnest(event_params) as event_param where event_date >= '2022-08-01' and event_date <= '2022-08-30' ) group by all ) ) ) qualify rank=1 ) ; 연습문제3, 연습문제4 쿼리는 동일하게 사용하고 event_name을 변경하면서 리텐션이 가장 높은 값을 추적 click_restaurant의 리텐션이 가장 높아 이를 핵심 이벤트로 지정해야 하나 싶긴 한데 결과가 조금 이상해서 쿼리 점검 필요 해보임.. 아래 쿼리에서 event_name만 click_payment로 변경하면 click_payment의 weekly retention select *, TRUNC(user_count / first_count, 3) AS ratio from ( select *, first_value(user_count) over(order by week_diff asc) as first_count from ( select week_diff, count(*) as user_count from ( select *, date_diff(datetime_week, first_week, week) as week_diff from ( select distinct user_pseudo_id, datetime_week, -- event_name, first_value(datetime_week) over (partition by user_pseudo_id order by datetime_week asc) as first_week from ( select *, DATETIME_TRUNC(CAST(event_date AS DATE), WEEK) AS datetime_week from ( select event_date, event_timestamp, user_pseudo_id, platform, event_name from `advanced.app_logs` where event_date >= '2022-08-01' and event_date <= '2022-08-30' and event_name='click_restaurant' ) ) ) ) group by week_diff ) ) order by week_diff ;

  • sql
  • Google-Analytics
  • firebase
  • google-sheets
  • bigquery
권기영 댓글 1 좋아요 0 조회수 95

이상한게 있습니다..

미해결

자바 ORM 표준 JPA 프로그래밍 - 기본편

학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? 예 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예 [질문 내용] 여기에 질문 내용을 남겨주세요. Team team = new Team(); team.setTeamNm("Team"); em.persist(team); Members members = new Members(); members.setName("good"); members.setHelloTeam(team); em.persist(members); em.flush(); em.clear(); Members finMembers = em.find(Members.class, members.getId()); List<Members> result = finMembers.getHelloTeam().getMembers(); System.out.println("aaaaaaaaaaaaaaaaaaaa="+result.size()); 뭔가 이상해요 em.flush(); em.clear(); 을 안쓰면 finMembers까지는 null 이 아닌데 results 까지는 null입니다. 왜 이런거예요 ???

  • java
  • jpa
junil jeong 댓글 2 좋아요 1 조회수 165

인기 태그

인프런 TOP Writers

주간 인기글