๐ฏ ๋ฑ๋ก ์์ ์ ๊ธฐ์ค์ผ๋ก ์ผ์ ๊ธฐ๊ฐ ๋์ ์ฌ์ฉ์๊ฐ ์ง์ํด์ ์ฌ์ฉํ๊ณ ์๋์ง๋ฅผ ์กฐ์ฌํ ๋
์ง์๋ฅ ๊ณผ ์ ์ฐฉ๋ฅ ์ ์ฌ์ฉํ๋ฉด ๊ฒฝํฅ์ ์ฝ๊ฒ ํ์ ํ ์ ์๋ค.
์ง์๋ฅ ๊ณผ ์ ์ฐฉ๋ฅ ์ด๋?
- ์ง์๋ฅ : ๋ฑ๋ก์ผ ๊ธฐ์ค์ผ๋ก ์ดํ ์ง์ ์ผ ๋์ ์ฌ์ฉ์๊ฐ ์๋น์ค๋ฅผ ์ผ๋ง๋ ์ด์ฉํ๋์ง ๋ํ๋ด๋ ์งํ
- ๋ฑ๋ก์ผ ์ดํ ๋งค์ผ ์๋น์ค๋ฅผ ์ฌ์ฉํ์ง ์๋๋ผ๋, ํ์ ๋ ์ง ์์ ์ฌ์ฉํ๋ค๋ฉด ์ง์์๋ก ์ทจ๊ธํจ
- ์ง๊ณ ๋ฐฉ๋ฒ : ๋ฑ๋ก์์ ์ฌ์ฉ์ ์๋ฅผ ์ง๊ณํ๊ณ , (์ฌ์ฉ์ ์ / ๋ฑ๋ก ์) ๋ก ๊ตฌํ๋ค.
- ์ ์ฐฉ๋ฅ : ๋ฑ๋ก์ผ ๊ธฐ์ค์ผ๋ก ์ดํ ์ง์ ํ 7์ผ ๋์ ์ฌ์ฉ์๊ฐ ์๋น์ค๋ฅผ ์ฌ์ฉํ๋์ง ๋ํ๋ด๋ ์งํ
- 7์ผ์ด๋ผ๋ ๊ธฐ๊ฐ ๋์ ํ ๋ฒ์ด๋ผ๋ ์๋น์ค๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์ ์ฐฉ์๋ก ๋ค๋ฃธ
- 7์ผ ์ ์ฐฉ๋ฅ ์ ๋ฑ๋ก ํ 1์ผ๋ถํฐ 7์ผ๊น์ง์ ์ ์ฐฉ๋ฅ ์ ๊ธฐ์ค์ผ๋ก ์ฐ์ถํจ
- 14์ผ ์ ์ฐฉ๋ฅ ์ ์ดํ 7์ผ(๋ฑ๋ก์ผ๋ถํฐ 8์ผ ํ๋ถํฐ 14์ผ๊น์ง์ ์ ์ฐฉ๋ฅ )
- ์ง๊ณ ๋ฐฉ๋ฒ : ์ฌ์ฉ์ ์ / ๋ฑ๋ก ์
- ์ฌ์ฉ์์๊ฒ ๊ธฐ๋ํ๋ ์ฌ์ฉ ์ฌ์ดํด์ ์๋น์ค๋ณ๋ก ๋ค๋ฅด๋ค.
- ์์ ๊ฒ์๊ณผ ๋ด์ค ์ฌ์ดํธ, SNS๋ ์ฌ์ฉ์๊ฐ ํํ์ด ๊ณ์ ์ด์ฉํ๊ธฐ๋ฅผ ๊ธฐ๋ํ ๊ฒ์ด๋ค ๐ ์ง์๋ฅ
- ์ด์ปค๋จธ์ค ์ฌ์ดํธ๋ ๋งค์ผ ์ผํํ๋ผ ๊ฒ์ ๊ธฐ๋ํ ๊ฒ์ด๋ค ๐ ์ ์ฐฉ๋ฅ
- ๋ฆฌ๋ทฐ ์ฌ์ดํธ๋ ์ฌ์ฉ์๊ฐ ๋ฌด์ธ๊ฐ๋ฅผ ์ฒดํํ ๋๋ง๋ค ์ฌ์ฉํ๊ธฐ๋ฅผ ๊ธฐ๋ํ ๊ฒ์ด๋ค ๐ ์ ์ฐฉ๋ฅ
๋ ์ง๋ณ N์ผ ์ง์๋ฅ ์ถ์ด
- ์ง์๋ฅ ์ ์ฌ๋ฆด ์ ์๋ ๋์ฑ ์ ํจ๊ณผ๊ฐ ์๋ํ ๋๋ก ์ํ๋๋์ง๋ฅผ ํ์ธํ๋ ค๋ฉด, ์ง์๋ฅ ์ ๋ ์ง์ ๋ฐ๋ผ ์ง๊ณํ ๋ฆฌํฌํธ๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค.
- ์๋น์ค๋ฅผ ๋ ํ๋ฐํ๊ฒ ํ๋ ค๋ฉด ๋ฑ๋ก ๋ค์ ๋ ์ ์ง์๋ฅ ์ ๋์ด๋ ๊ฒ์ด ์ค์ํ๋ค.
โถ๏ธ ๋ค์๋ (1์ผ) ์ง์๋ฅ ์ง๊ณ
- ๋ค์๋ ์ง์๋ฅ ์ '์ง์ ํ ๋ ์ง์ ๋ฑ๋กํ ์ฌ์ฉ์ ์ค ๋ค์๋ ์๋ ์๋น์ค๋ฅผ ์ฌ์ฉํ ์ฌ๋์ ๋น์จ'์ด๋ค.
- ์ง์ ํ ๋ ์ง ๋ค์์ ์ฌ์ฉํ ์ฌ์ฉ์์ 1, ์ฌ์ฉํ์ง ์์ ์ฌ์ฉ์์ 0์ด๋ผ๋ ํ๋๊ทธ๋ฅผ ๋ถ์ด๊ณ , ์ด๋ฌํ ๊ฐ์ AVG ํจ์๋ฅผ ์ ์ฉํด ํ๊ท ์ ๊ตฌํ๋ ๋ฐฉ๋ฒ์ด ๊ฐ๋จํ๋ค.
- ๋จ, ๋ค์๋ ์ง์๋ฅ ์ ์ง๊ณํ๋ ค๋ฉด ๋ค์๋ ์ ๋ก๊ทธ ๋ฐ์ดํฐ๊ฐ ๋ชจ๋ ์์ฌ ์์ด์ผ ํ๋ค!!
๐ ๋ฑ๋ก์ผ ๋ค์๋ ์์ ํ ์ฌ์ฉ์๊ฐ ์ ๋ง๋ก 0์ธ ๊ฒฝ์ฐ์, ๋ก๊ทธ๊ฐ ์์ง ์์ด์ง ์์์ 0๋ช ์ผ๋ก ๋์ค๋ ๊ฒฝ์ฐ๋ฅผ ๊ตฌ๋ถํด์ผ ํ๊ธฐ ๋๋ฌธ
๐ ์ฌ๊ธฐ์๋ ๋ก๊ทธ ์ง๊ณ ๊ธฐ๊ฐ ์ค ๊ฐ์ฅ ์ต์ ๋ ์ง๋ฅผ ์ถ์ถํ๊ณ , ์ด ์ผ์๋ฅผ ๋๋ ๊ธฐ๊ฐ์ ์ง์๋ฅ ์ NULL๋ก ์ถ๋ ฅํ๊ฒ ํ๋ค.
- ๋ก๊ทธ์ ์ต๊ทผ ๋ ์ง ์ถ์ถํ๊ธฐ
- ์ฌ์ฉ์๋ณ ๋ฑ๋ก์ผ๊ณผ ๋ค์๋ ์ ๋ ์ง๋ฅผ ์ง๊ณํ๊ธฐ
โถ๏ธ ๋ฑ๋ก ๋ค์ ๋ ์ง : CAST(u.register_date::date + '1 day'::INTERVAL, date)
WITH
action_log_with_mst_users AS (
SELECT u.user_id
, u.register_date
, cast(a.stamp AS date) AS action_date --์ก์
๋ ์ง ์๋ฃํ ๋ณ
, max(cast(a.stamp AS date)) OVER () AS last_date -- ์ ์ฒด ๋ก๊ทธ์์ ๊ฐ์ฅ ์ต๊ทผ ์ก์
๋ ์ง
, cast(u.register_date::date + '1 day'::INTERVAL AS date) AS next_day_1
FROM mst_users AS u
LEFT JOIN action_log AS a
ON u.user_id = a.user_id
)
SELECT *
FROM action_log_with_mst_users
ORDER BY register_date
;
3. ์ง์ ํ ๋ ์ ๋ค์ ๋ ์ ์ก์
์ ํ๋์ง 0๊ณผ 1๋ก ํ์ํ๊ธฐ
→ ์ง์ ํ ๋ ์ ๋ค์๋ ์ด ๋ก๊ทธ์ ๊ฐ์ฅ ์ต๊ทผ ๋ ์ง๋ฅผ ๋๋ ๊ฒฝ์ฐ์๋ NULL๋ก ์ฒ๋ฆฌ
- ๋ฑ๋ก์ผ ๋ค์๋ ์ด ๋ก๊ทธ์ ์ต์ ๋ ์ง ์ด์ ์ธ์ง ๋จผ์ ์กฐ๊ฑด์ case when ์ผ๋ก ๊ฑธ๊ณ , ๋ฑ๋ก์ผ ๋ค์ ๋ ์ ์ก์ ์ด ์ผ์ด๋ฌ๋์ง ํ ๋ฒ ๋ case when์ผ๋ก ํ์ธํ์ฌ 1, 0์ ๋ฐํ ๐ SIGN ํจ์
WITH
action_log_with_mst_users AS (
SELECT u.user_id
, u.register_date
, cast(a.stamp AS date) AS action_date --์ก์
๋ ์ง ์๋ฃํ ๋ณ
, max(cast(a.stamp AS date)) OVER () AS lastest_date -- ์ ์ฒด ๋ก๊ทธ์์ ๊ฐ์ฅ ์ต๊ทผ ์ก์
๋ ์ง
, cast(u.register_date::date + '1 day'::INTERVAL AS date) AS next_day_1
FROM mst_users AS u
LEFT JOIN action_log AS a
ON u.user_id = a.user_id
)
-- ์ฌ์ฉ์์ ์ก์
ํ๋๊ทธ๋ฅผ ๊ณ์ฐ --
,user_action_flag AS (
SELECT user_id
, register_date
, SIGN(
sum(CASE WHEN next_day_1 <= lastest_date THEN
CASE WHEN next_day_1 = action_date THEN 1 ELSE 0 END
END)
) AS next_1_day_actioin
FROM action_log_with_mst_users
GROUP BY user_id, register_date
)
SELECT *
FROM user_action_flag
ORDER BY register_date, user_id ;
- ์ฌ๊ธฐ์ ๋ ์ง๋ณ๋ก, next_1_day_action์ ํ๊ท ์ ๊ตฌํ๊ณ 100์ ๊ณฑํ๋ฉด 1์ผ ์ดํ์ ์ง์๋ฅ ์ ๊ตฌํ ์ ์๋ค.
-- user_action_flag ๊น์ง ๋์ผ --
SELECT register_date
, avg(100.0 * next_1_day_actioin) AS repeat_rate_1_day
FROM user_action_flag
GROUP BY register_date
ORDER BY register_date
;
๐ฏ ์ข ํฉ ์ฟผ๋ฆฌ | ์ง์๋ฅ ์งํ๋ฅผ ๊ด๋ฆฌํ๋ ๋ง์คํฐ ํ ์ด๋ธ์ ์์ฑํ๋ ์ฟผ๋ฆฌ
1. ์งํ ๋ง์คํฐ ์์ฑ
- PostgreSQL์ VALUES๋ก ํ ์ด๋ธ์ ์์ฑํ ์ ์๋ค.
WITH
repeat_interval(index_name, interval_day) AS (
VALUES
('01 day repeat', 1)
,('02 day repeat', 2)
,('03 day repeat', 3)
,('04 day repeat', 4)
,('05 day repeat', 5)
,('06 day repeat', 6)
,('07 day repeat', 7)
)
SELECT *
FROM repeat_interval
ORDER BY index_name
;
2. ๋ ์ง๋ณ ์ง์๋ฅ ๊ณ์ฐ ์ฟผ๋ฆฌ
- action_log_with_index_date ํ
์ด๋ธ
- ์์์ ๋ง๋ repeat_interval์ CROSS JOIN ํ๋ค.
- ๊ฐ ๋ก๊ทธ์ ๋ ์ง๋ฅผ date ํ์์ผ๋ก ๋ฐ๊ฟ์ฃผ๊ณ
- ์ ์ ๋ณ ๊ฐ์ฅ ์ต์ ๋ก๊ทธ๋ ๊ตฌํด์ค๋ค (max)
- ์ง์๋ฅ ์ ๊ณ์ฐํ๊ณ ์ถ์ ๋ ์ง๋ฅผ interval '1 day'์ ๊ณฑํด์ฃผ๊ณ ์ด๋ฅผ ๋ฑ๋ก์ผ์ ๋ํด์ index_date๋ฅผ ๋ง๋ ๋ค
- user_action_flag ํ
์ด๋ธ
- ๋ฑ๋ก์ผ ๋ค์ ๋ ์ง(๊ธฐ์ค๋ ์ง)์ธ index_date๊ฐ ๊ฐ์ฅ ์ต์ ๋ก๊ทธ ๋ ์ง๋ณด๋ค ์ด์ ์ธ์ง ํ์ธํ๊ณ ,
index_date๊ฐ action_date์ ๋์ผํ๋ฉด 1, ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ 0์ ๋ฐํ
- ๋ฑ๋ก์ผ ๋ค์ ๋ ์ง(๊ธฐ์ค๋ ์ง)์ธ index_date๊ฐ ๊ฐ์ฅ ์ต์ ๋ก๊ทธ ๋ ์ง๋ณด๋ค ์ด์ ์ธ์ง ํ์ธํ๊ณ ,
- ๋ง์ง๋ง SELECT์
- ๋ฑ๋ก์ผ๊ณผ index_name(ํ์ธํ๊ณ ์ถ์ ์ง์๋ฅ ๋ ์ง ๊ธฐ์ค)์ ๊ธฐ์ค์ผ๋ก ๊ทธ๋ฃนํํ์ฌ ์ง์๋ฅ ํ๊ท ์ ๊ตฌํ๋ค.
WITH
repeat_interval(index_name, interval_date) AS (
VALUES
('01 day repeat', 1)
,('02 day repeat', 2)
,('03 day repeat', 3)
,('04 day repeat', 4)
,('05 day repeat', 5)
,('06 day repeat', 6)
,('07 day repeat', 7)
)
, action_log_with_index_date AS (
SELECT u.user_id
, u.register_date
, cast(a.stamp AS date) AS action_date
, max(CAST(a.stamp AS date)) OVER() AS lastest_date
, r.index_name --๋ฑ๋ก์ผ๋ก๋ถํฐ n์ผ ํ์ ๋ ์ง
, cast(cast(u.register_date AS date) + INTERVAL '1 day' * r.interval_date AS date) AS index_date
FROM mst_users AS u
LEFT JOIN action_log AS a ON u.user_id = a.user_id
CROSS JOIN repeat_interval AS r
)
, user_action_flag AS (
SELECT user_id
, register_date
, index_name
, sign(
sum(CASE WHEN index_date <= lastest_date THEN
CASE WHEN index_date = action_date THEN 1 ELSE 0 END
END
)
) AS index_date_action
FROM action_log_with_index_date
GROUP BY user_id, register_date, index_name, index_date
)
SELECT register_date
, index_name
, avg(100.0 * index_date_action) AS repeat_rate
FROM user_action_flag
GROUP BY register_date, index_name
ORDER BY register_date, index_name
;
728x90