簡體   English   中英

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_BUCKETGENERATE_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM