統(tǒng)計(jì)數(shù)據(jù)庫中連續(xù)相同的數(shù)據(jù),如連續(xù)登錄天數(shù)、重復(fù)訂單等,核心是通過分組標(biāo)記連續(xù)區(qū)間。統(tǒng)計(jì)用戶連續(xù)登錄天數(shù),需按用戶ID分組后,用DATEDIFF(date, ROW_NUMBER())標(biāo)記連續(xù)區(qū)間。本文詳細(xì)為大家介紹關(guān)于數(shù)據(jù)庫統(tǒng)計(jì)連續(xù)相同數(shù)據(jù)的詳細(xì)方法與步驟。
數(shù)據(jù)庫統(tǒng)計(jì)連續(xù)相同數(shù)據(jù)
要讓數(shù)據(jù)庫統(tǒng)計(jì)連續(xù)相同的數(shù)據(jù),通常需要結(jié)合窗口函數(shù)或自連接來實(shí)現(xiàn)。以下是針對(duì)不同數(shù)據(jù)庫的通用方法和示例:
核心思路
分組連續(xù)數(shù)據(jù):通過比較當(dāng)前行與前一行的值,標(biāo)記連續(xù)相同數(shù)據(jù)的起始和結(jié)束位置。
計(jì)算連續(xù)次數(shù):對(duì)每個(gè)分組內(nèi)的數(shù)據(jù)計(jì)數(shù),得到連續(xù)出現(xiàn)的次數(shù)。
方法一:使用窗口函數(shù)
適用于支持窗口函數(shù)的數(shù)據(jù)庫。
示例場景
統(tǒng)計(jì)表中連續(xù)相同狀態(tài)的次數(shù)。
SQL 實(shí)現(xiàn)
sqlWITH MarkedGroups AS (SELECT id,date,status,-- 如果當(dāng)前行與前一行狀態(tài)相同,則繼承組ID,否則新組IDSUM(CASE WHEN status != LAG(status) OVER (ORDER BY date) OR LAG(status) OVER (ORDER BY date) IS NULL THEN 1 ELSE 0 END) OVER (ORDER BY date) AS group_idFROM your_table),GroupedStats AS (SELECT group_id,status,COUNT(*) AS consecutive_countFROM MarkedGroupsWHERE status = 1 -- 篩選目標(biāo)狀態(tài)GROUP BY group_id, status)SELECT status,MAX(consecutive_count) AS max_consecutive_days -- 找出最長連續(xù)次數(shù)FROM GroupedStatsGROUP BY status;
關(guān)鍵點(diǎn)
LAG(status) OVER (ORDER BY date):獲取前一行的狀態(tài)。
SUM(...) OVER (ORDER BY date):為連續(xù)相同狀態(tài)分配相同的 group_id。
最終按 group_id 分組統(tǒng)計(jì)次數(shù)。
方法二:自連接
如果數(shù)據(jù)庫不支持窗口函數(shù),可以通過自連接實(shí)現(xiàn)。
示例場景
統(tǒng)計(jì)連續(xù)相同的 status 出現(xiàn)的最大次數(shù)。
SQL 實(shí)現(xiàn)
sqlSELECT t1.status,MAX(t1.consecutive_count) AS max_consecutive_countFROM (SELECT a.id,a.status,COUNT(*) AS consecutive_countFROM your_table aJOIN your_table b ON a.id = b.id + 1 -- 假設(shè)按id升序排列WHERE a.status = b.statusGROUP BY a.id, a.status) t1GROUP BY t1.status;
局限性
需要數(shù)據(jù)有明確的排序字段。
性能較差,大數(shù)據(jù)量時(shí)可能超時(shí)。
方法三:使用變量。
MySQL 5.7 及以下版本可通過用戶變量模擬窗口函數(shù)。
SQL 實(shí)現(xiàn)
sqlSELECT status,MAX(consecutive_count) AS max_consecutive_countFROM (SELECT id,date,status,@group_id := IF(status = @prev_status, @group_id, @group_id + 1) AS group_id,@prev_status := status,@consecutive_count := IF(status = @prev_status, @consecutive_count + 1, 1) AS consecutive_countFROM your_table,(SELECT @group_id := 0, @prev_status := NULL, @consecutive_count := 0) AS varsORDER BY date) tWHERE status = 1 -- 篩選目標(biāo)狀態(tài)GROUP BY group_id, status;
實(shí)際應(yīng)用案例
案例1:統(tǒng)計(jì)用戶連續(xù)登錄天數(shù)
假設(shè)表 user_logins 包含字段 user_id, login_date,需統(tǒng)計(jì)每個(gè)用戶最長連續(xù)登錄天數(shù)。
sqlWITH MarkedDays AS (SELECT user_id,login_date,DATE_SUB(login_date, INTERVAL ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) DAY) AS date_groupFROM user_logins),GroupedStats AS (SELECT user_id,date_group,COUNT(*) AS consecutive_daysFROM MarkedDaysGROUP BY user_id, date_group)SELECT user_id,MAX(consecutive_days) AS max_consecutive_loginsFROM GroupedStatsGROUP BY user_id;
案例2:統(tǒng)計(jì)股票連續(xù)上漲天數(shù)
假設(shè)表 stock_prices 包含字段 date, price,需統(tǒng)計(jì)最長連續(xù)上漲天數(shù)。
sqlWITH PriceChanges AS (SELECT date,price,CASE WHEN price > LAG(price) OVER (ORDER BY date) THEN 1 ELSE 0 END AS is_increasingFROM stock_prices),MarkedGroups AS (SELECT date,is_increasing,SUM(CASE WHEN is_increasing = 0 THEN 1 ELSE 0 END) OVER (ORDER BY date) AS group_idFROM PriceChangesWHERE is_increasing = 1)SELECT COUNT(*) AS consecutive_increasing_daysFROM MarkedGroupsGROUP BY group_idORDER BY consecutive_increasing_days DESCLIMIT 1;
以上就是數(shù)據(jù)庫統(tǒng)計(jì)連續(xù)的詳細(xì)步驟,根據(jù)實(shí)際數(shù)據(jù)庫類型和版本選擇合適的方法即可!確保數(shù)據(jù)有明確的排序字段,否則無法正確判斷連續(xù)性。優(yōu)先使用窗口函數(shù),代碼簡潔且性能好。