商業上最常被問到、也最令人擔心的問題就是
「這個用戶是不是快流失了?」
今天要分享如何用 SQL 找出「潛在流失用戶」,在用戶流失前想辦法先挽留他們!
情境假設
當用戶連續三天沒有登入時,很可能代表他們對產品失去興趣,這類用戶就是我們需要特別關注的對象
現有資訊
登入紀錄存在一張 login_logs 表中,欄位如下:

資料需求
找到像 A001 這樣沒有連續登入三天的用戶
SQL 寫法
第一步:只取每個使用者的登入日期,避免重複紀錄干擾
WITH login_dates AS (
SELECT
DISTINCT user_id,
login_date
FROM login_logs
),
第二步:使用 ROW_NUMBER 為每位用戶的登入紀錄依時間排序
ranked AS (
SELECT
user_id,
login_date,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) AS rn
FROM login_dates
),
產生表格如下:

第三步:用「日期減掉編號」當作群組鍵 gap_key,抓出連續段
grouped AS (
SELECT
user_id,
DATE_SUB(login_date, INTERVAL rn DAY) AS gap_key
-- 差值一樣代表連續日期
FROM ranked
),
產生表格如下:

每個 user 的連續天會變成相同的 gap_key,A003 的三筆 gap_key 一樣,代表是連續登入三天!
第四步:分組後數每組的天數,如果有 3 天或以上就是連續登入
grouped_dates AS (
SELECT
user_id,
COUNT(*) AS streak_length
FROM grouped
GROUP BY user_id, gap_key
HAVING streak_length >= 3 -- 連續登入三天以上(活躍用戶)
),
產生表格如下:

找到了有「連續三天登入」的用戶
第五步:找出沒有連續登入的人!
SELECT
DISTINCT user_id
FROM login_logs
WHERE user_id NOT IN (
SELECT user_id
FROM grouped_dates
)
就會發現A001與A002這兩位用戶沒有連續登入 3 天,我們就可以寄通知提醒他們!
SQL 關鍵技能
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date):為每位使用者的登入紀錄依時間排序。DATE_SUB(login_date, INTERVAL rn DAY):用登入日期減去 row number,讓連續天數形成「一樣的差值」,就能判斷是否連續。GROUP BY user_id, gap_key:用差值分組,每組就是一段連續日期。HAVING streak_length >= 3:保留連續三天或以上的登入紀錄。NOT IN (...):找出不在這些連續登入段的使用者,就是我們要關心的「潛在流失用戶」。
重點價值
這種「連續天數判斷」的技巧,在實務中超級實用,例如:
- 連續幾天沒打卡的員工
- 連續幾天訂餐的 VIP 客戶
- 連續幾天沒開啟 App 的用戶
- 連續使用優惠券的顧客
- 連續開啟廣告的賣家
- 連續退貨的消費者
這篇教你用 SQL 就能辦到!
只要有「時間」跟「用戶」這兩個欄位,都可以套這個邏輯!















