Sql-Server
查詢以查找指定日期之間的活動天數(狀態 = ON 的天數)
我有一張桌子,如下所示:
create table z_test_duration ( Days date, Status char(8) );
樣本數據如下:
想要的結果是這樣的
到目前為止,我的解決方案是:
select min(days) on_date, off_day off_date, off_day - min(days) cnt from (select t1.off_day, t1.prev_offday, t2.days from ( select t.days off_day, nvl(lag(t.days, 1) over(order by t.days),convert(datetime, '1/1/2022') - 100) prev_offday from z_test_duration t where t.status = 'off' ) t1 inner join z_test_duration t2 on t2.days > t1.prev_offday and t2.days < t1.off_day) group by off_day;
我在想是否有更好的方法來解決這個問題,如果你能分享你解決這個問題的方法,我將不勝感激。
提前致謝。
這是一個“孤島”問題。
一種流行且有效的解決方案是按所需順序對行進行編號。當序列中有間隙時,排序列和行號之間的差異也會跳躍。
讓我們一步一步來看看。一、編號:
SELECT Z.*, Seq = Z.[Days], -- ordering column rn = ROW_NUMBER() OVER (ORDER BY Z.[Days]) -- numbering FROM dbo.z_test_duration AS Z WHERE Z.[Status] = 'on';
請注意,
Seq
值以相同的速度增加,rn
直到出現間隙。rn
通過從Seq
值中減去,我們可以更清楚地看到這一點。這裡唯一稍微複雜的
Seq
是 adate
,因此我們需要在減去之前將其轉換為數字。我在DATEDIFF
這裡使用了這個函式,但是任何將日期轉換為數字的一致方法都可以。SELECT Z.*, Seq = Z.[Days], diff = DATEDIFF(DAY, '2022-01-01', Z.[Days]) - ROW_NUMBER() OVER ( ORDER BY Z.[Days]) FROM dbo.z_test_duration AS Z WHERE Z.[Status] = 'on';
diff
對於組中的每個連續元素,這些值都是相同的。現在我們知道如何分組了,最終查詢直接如下:
SELECT ON_DATE = MIN(G.Seq), OFF_DATE = DATEADD(DAY, 1, MAX(G.Seq)), COUNT_OF_ACTIVE_DAYS = 1 + DATEDIFF(DAY, MIN(G.Seq), MAX(G.Seq)) FROM ( SELECT Z.*, Seq = Z.[Days], grp = DATEDIFF(DAY, '2022-01-01', Z.[Days]) - ROW_NUMBER() OVER ( ORDER BY Z.[Days]) FROM dbo.z_test_duration AS Z WHERE Z.[Status] = 'on' ) AS G GROUP BY G.grp;