첫 임기 연도, 기간별 코호트 숫자
이전 게시글에 LEFT JOIN
을 한 이유에 대해 설명하지 않은 것 같아서 작성해보려고 한다. 만약 임기 시작 날짜와 끝나는 날짜가 다음과 같다고 가정한다.
- term_start : 2018-01-03
- term_end : 2018-11-06
date_dim 테이블의 date 컬럼에서 12월 31일에 해당하는 날짜만을 가지고 JOIN 하기 때문에 해당 날짜와 매칭되는 날짜가 존재하지 않는다.
그런 경우 date 컬럼에 NULL이 입력되며, 추후 NULL을 COALESCE 함수를 통해 0으로 변경해주는 것이다.
JOIN 테이블의 첫 임기 시작 날짜에서 연도만을 추출한다.
date - first_term을 통해 period를 계산하고, NULL은 0으로 변경해준다. 이후 고유한 ID들의 COUNT를 계산하면 코호트 숫자가 계산된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT
DATE_PART('year', A.first_term) AS first_year,
COALESCE(DATE_PART('year', AGE(C.date, A.first_term)), 0) AS period,
COUNT(DISTINCT A.id_bioguide) AS cohort_retained
FROM
(
SELECT id_bioguide, MIN(term_start) AS first_term
FROM legislators_terms
GROUP BY id_bioguide
) AS A JOIN legislators_terms AS B ON A.id_bioguide= B.id_bioguide
LEFT JOIN date_dim AS C ON C.date BETWEEN B.term_start AND B.term_end
AND C.month_name = 'December' AND C.day_of_month = 31
GROUP BY 1, 2
ORDER BY 1, 2;
첫 임기 시작 연도별, 기간별 코호트 비율
- 위 쿼리를 서브쿼리로 사용한다.
- 각 첫 임기 시작 연도별로 period를 오름차순하였을 때 첫 번째 코호트 값과 비율을 계산한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
SELECT first_year, period, cohort_retained, FIRST_VALUE(cohort_retained) OVER(PARTITION BY first_year ORDER BY period) AS cohort_size, ROUND(cohort_retained * 1.0 / FIRST_VALUE(cohort_retained) OVER(PARTITION BY first_year ORDER BY period), 2) AS pct_retained FROM ( SELECT DATE_PART('year', A.first_term) AS first_year, COALESCE(DATE_PART('year', AGE(C.date, A.first_term)), 0) AS period, COUNT(DISTINCT A.id_bioguide) AS cohort_retained FROM ( SELECT id_bioguide, MIN(term_start) AS first_term FROM legislators_terms GROUP BY id_bioguide ) AS A JOIN legislators_terms AS B ON A.id_bioguide= B.id_bioguide LEFT JOIN date_dim AS C ON C.date BETWEEN B.term_start AND B.term_end AND C.month_name = 'December' AND C.day_of_month = 31 GROUP BY 1, 2 ORDER BY 1, 2 ) AS sub ORDER BY 1,2;
ID별 first_term과 state
- ID별 term_start의 최소값을 계산한다.
- ID별로 term_start를 오름차순 했을 때 처음 오는 state값을 조회한다.
1 2 3 4 5
SELECT DISTINCT(id_bioguide), MIN(term_start) OVER(PARTITION BY id_bioguide) AS first_term, FIRST_VALUE(state) OVER(PARTITION BY id_bioguide ORDER BY term_start ASC) AS first_state FROM legislators_terms;
첫 임기 state별, period별 코호트 숫자와 비율
- 위의 쿼리를 서브쿼리로 사용한다.
- date_dim 테이블과 JOIN한다. JOIN 기준은 앞서 해온 JOIN과 같다.
- 첫 임기 시작 날짜 대신 state를 기준으로 그루핑하여 코호트 숫자와 비율을 계산한다.
- 앞서 해온 쿼리와 대부분 동일하되 first_term이 first_state로 변경된 것이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
SELECT first_state, period, cohort_retained, FIRST_VALUE(cohort_retained) OVER(PARTITION BY first_state ORDER BY period ASC) AS cohort_size, ROUND(cohort_retained * 1.0 / FIRST_VALUE(cohort_retained) OVER(PARTITION BY first_state ORDER BY period ASC), 2) AS pct_retained FROM ( SELECT A.first_state, COALESCE(DATE_PART('year', AGE(C.date, A.first_term)), 0) AS period, COUNT(DISTINCT(A.id_bioguide)) AS cohort_retained FROM ( SELECT DISTINCT(id_bioguide), MIN(term_start) OVER(PARTITION BY id_bioguide) AS first_term, FIRST_VALUE(state) OVER(PARTITION BY id_bioguide ORDER BY term_start ASC) AS first_state FROM legislators_terms ) AS A JOIN legislators_terms AS B ON A.id_bioguide = B.id_bioguide LEFT JOIN date_dim AS C ON C.date BETWEEN B.term_start AND B.term_end AND C.month_name = 'December' AND C.day_of_month = 31 GROUP BY 1, 2 ) AS sub ORDER BY first_state ASC, period ASC;