[英]How to split a time frame in one row to different quarters in different rows in T-SQL
[英]T-SQL Calculating Time Quarters
Person Beginning Ending Length
1 1/1/2022 12:25:00 1/1/2022 13:05:00 2400
我想跨季度桶解析這條記錄以及每個季度桶中花費的長度。
Person Beginning Ending Length Bucket
1 1/1/2022 12:25:00 1/1/2022 13:05:00 300 12:15
1 1/1/2022 12:25:00 1/1/2022 13:05:00 900 12:30
1 1/1/2022 12:25:00 1/1/2022 13:05:00 900 12:45
1 1/1/2022 12:25:00 1/1/2022 13:05:00 300 13:00
只是另一種選擇......蠻力
示例或dbFiddle
Select A.Person
,A.[Begining]
,A.[Ending]
,B.[Length]
,Bucket = left(convert(varchar(10),Bucket,8),5)
From YourTable A
Cross Apply ( Select [Length] = sum(1)
,Bucket
From (Select Top (datediff(SECOND,[Begining],[Ending])) D=dateadd(SECOND,-1+Row_Number() Over (Order By (Select NULL)),[Begining]) From master..spt_values n1, master..spt_values n2 ) B1
Cross Apply ( values (dateadd(minute,(datediff(minute,0,D) / 15 ) * 15,0) ) ) C(Bucket)
Group By Bucket
) B
結果
一種方法是使用一些“魔術”日期和一個 Tally。 這不是特別漂亮,但看起來像這樣:
SELECT V.Person,
V.[Start],
V.[End],
V.Length,
DATEDIFF(SECOND,CASE WHEN V.[Start] > R.BucketStart THEN V.[Start] ELSE R.BucketStart END, CASE WHEN V.[End] < R.BucketEnd THEN V.[End] ELSE R.BucketEnd END) AS Length
FROM (VALUES(1,CONVERT(datetime2(0),'1/1/2022 12:25:00',103),CONVERT(datetime2(0),'1/1/2022 13:05:00',103),2400))V(Person, [Start], [End], Length)
CROSS APPLY (VALUES(DATEADD(MINUTE, (DATEDIFF(MINUTE,0,[Start])/15)*15,0),DATEADD(MINUTE, (DATEDIFF(MINUTE,0,[End])/15)*15,0)))B(StartBucket,EndBucket)
CROSS APPLY fn.Tally(DATEDIFF(MINUTE,B.StartBucket,B.EndBucket) / 15,0) T
CROSS APPLY (VALUES(DATEADD(MINUTE,T.I*15,B.StartBucket),DATEADD(MINUTE,(T.I+1)*15,B.StartBucket)))R(BucketStart,BucketEnd);
請注意使用 function Tally
,其定義如下:
CREATE FUNCTION [fn].[Tally] (@End bigint, @StartAtOne bit)
RETURNS table
AS RETURN
WITH N AS(
SELECT N
FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)),
Tally AS(
SELECT 0 AS I
WHERE @StartAtOne = 0
UNION ALL
SELECT TOP (@End)
ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I
FROM N N1, N N2, N N3, N N4, N N5, N N6, N N7, N N8)
SELECT I
FROM Tally;
GO
在 SQL 服務器的下一版本(2022 年)上,實際上更容易,因為您可以訪問DATE_BUCKET
和GENERATE_SERIES
(盡管出於故意未公開的原因,我在這里不使用GENERATE_SERIES
)。
SELECT V.Person,
V.[Start],
V.[End],
V.Length,
DATEDIFF(SECOND,CASE WHEN V.[Start] > R.BucketStart THEN V.[Start] ELSE R.BucketStart END, CASE WHEN V.[End] < R.BucketEnd THEN V.[End] ELSE R.BucketEnd END) AS Length,
CONVERT(time(0),R.BucketStart) AS Bucket
FROM (VALUES(1,CONVERT(datetime2(0),'1/1/2022 12:25:00',103),CONVERT(datetime2(0),'1/1/2022 13:05:00',103),2400))V(Person, [Start], [End], Length)
CROSS APPLY (VALUES(DATE_BUCKET(MINUTE, 15, V.[Start]),DATE_BUCKET(MINUTE, 15, V.[End])))B(StartBucket,EndBucket)
CROSS APPLY fn.Tally(DATEDIFF(MINUTE,B.StartBucket,B.EndBucket)/15,0) T
CROSS APPLY (VALUES(DATEADD(MINUTE,T.I*15,B.StartBucket),DATEADD(MINUTE,(T.I+1)*15,B.StartBucket)))R(BucketStart,BucketEnd);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.