生成动态自定义时间间隔

时间:2018-04-19 17:09:02

标签: sql-server-2014

我正在开发一个项目,该项目需要能够在非标准用户定义的时间间隔内动态分组源数据的报表,例如指定开始和结束范围内的生产班次。示例用户可能希望在过去两天按班次查看生产信息组。 我创建了一个名为“IntervalConfiguration”的表,它存储了使用以下数据创建分组间隔所需的配置信息:

IntervalType                SubIntervalType     IntervalDuration     IntervalDurationUnits  IntervalStartReferenceTime IntervalRepeatDuration IntervalRepeatDurationUnits
-------------------------   ------------------- -------------------- ---------------------  -------------------------- ---------------------- ---------------------------
Production Day              ProductionDay       1                    Days                   2013-01-07 07:00:00.000    1                      Days
Production Month            ProductionMonth     1                    Months                 2013-01-01 07:00:00.000    1                      Months
Production Week             ProductionWeek      1                    Weeks                  2013-01-07 08:45:00.000    1                      Weeks
Production Year             ProductionYear      1                    Years                  2013-01-01 08:45:00.000    1                      Years
Site A - Production Shift   Day                 12                   Hours                  2013-01-06 07:00:00.000    24                     Hours
Site A - Production Shift   Night               12                   Hours                  2013-01-06 19:00:00.000    24                     Hours
Site B - Production Shift   Day                 12                   Hours                  2013-01-06 06:45:00.000    24                     Hours
Site B - Production Shift   Night               12                   Hours                  2013-01-06 18:45:00.000    24                     Hours

如果用户选择“站点A - 生产班次”作为报告的分组间隔,开始日期为“01/01/2018”,结束日期为“01/05/2018”,则报告必须创建日班的分组间隔,其中日班时间从早上7点开始,到晚上7点结束,夜间班次从晚上7点开始,到第二天早上7点结束。 此外,只应返回完全包含在开始日期和结束日期内的分组间隔。下面是所描述方案的预期分组间隔的示例。

SubIntervalType     IntervalStart            IntervalEnd             
----------------    -----------------------  ----------------------- 
Day                 2018-01-01 07:00:00.000  2018-01-01 19:00:00.000 
Night               2018-01-01 19:00:00.000  2018-01-02 07:00:00.000 
Day                 2018-01-02 07:00:00.000  2018-01-02 19:00:00.000 
Night               2018-01-02 19:00:00.000  2018-01-03 07:00:00.000 
Day                 2018-01-03 07:00:00.000  2018-01-03 19:00:00.000 
Night               2018-01-03 19:00:00.000  2018-01-04 07:00:00.000 
Day                 2018-01-04 07:00:00.000  2018-01-04 19:00:00.000

如果用户选择生产月作为分组间隔,开始日期为'01 / 01/2018'且结束日期为'01 / 01/2011',则报告应生成以下分组间隔。

SubIntervalType     IntervalStart           IntervalEnd            
-----------------   ----------------------- -----------------------
ProductionMonth     2018-01-01 07:00:00.000 2018-02-01 07:00:00.000
ProductionMonth     2018-02-01 07:00:00.000 2018-03-01 07:00:00.000
ProductionMonth     2018-03-01 07:00:00.000 2018-04-01 07:00:00.000
ProductionMonth     2018-04-01 07:00:00.000 2018-05-01 07:00:00.000
ProductionMonth     2018-05-01 07:00:00.000 2018-06-01 07:00:00.000
ProductionMonth     2018-06-01 07:00:00.000 2018-07-01 07:00:00.000
ProductionMonth     2018-07-01 07:00:00.000 2018-08-01 07:00:00.000
ProductionMonth     2018-08-01 07:00:00.000 2018-09-01 07:00:00.000
ProductionMonth     2018-09-01 07:00:00.000 2018-10-01 07:00:00.000
ProductionMonth     2018-10-01 07:00:00.000 2018-11-01 07:00:00.000
ProductionMonth     2018-11-01 07:00:00.000 2018-12-01 07:00:00.000

我已经开始构建下面的表值函数来动态创建所需的分组间隔。

CREATE FUNCTION [dbo].[GetIntervals]
(
    @dateRangeStart datetime,
    @dateRangeEnd   datetime,
    @groupByInterval    NVARCHAR(200)
)
RETURNS @Intervals TABLE (
    IntervalType            NVARCHAR(100)
    ,SubIntervalType        NVARCHAR(100)
    ,IntervalStart          DATETIME
    ,IntervalEnd                DATETIME
    ,IntervalDurationSeconds    FLOAT
)
AS
BEGIN

    DECLARE @activeIntervalDateTime DATETIME = DATEADD(millisecond, 3, @dateRangeStart);
    DECLARE @intervalStartTime DATETIME = DATEADD(s, 1, @dateRangeStart);
    DECLARE @intervalEndTime DATETIME = DATEADD(s, 1, @dateRangeStart);
    DECLARE @intervalDurationSeconds FLOAT;
    DECLARE @intervalName NVARCHAR(100);
    DECLARE @subIntervalType NVARCHAR(100);

    WHILE @intervalStartTime <= @dateRangeEnd
    BEGIN

        SELECT   TOP 1
                 @intervalName = IntervalType ,@subIntervalType = SubIntervalType , @intervalStartTime = IntervalStart, @intervalEndTime = IntervalEnd
        FROM    (SELECT  IntervalType, SubIntervalType, IntervalDuration, IntervalDurationUnits,
                            IntervalRepeatDuration, IntervalRepeatDurationUnits,
                            CASE IntervalRepeatDurationUnits
                             WHEN 'Hours' THEN (DateAdd(HH, (DateDiff(HH, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration,  IntervalStartReferenceTime))
                             WHEN 'Days' THEN (DateAdd(D, (DateDiff(D, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration,  IntervalStartReferenceTime))
                             WHEN 'Months'THEN (DateAdd(MM, (DateDiff(MM, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration,  IntervalStartReferenceTime))
                             END AS IntervalStart,
                            CASE IntervalRepeatDurationUnits
                             WHEN 'Hours' THEN (DateAdd(HH, IntervalDuration, DateAdd(HH, (DateDiff(HH, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration,  IntervalStartReferenceTime)))
                             WHEN 'Days' THEN 
                                CASE IntervalDurationUnits
                                WHEN 'Hours' THEN (DateAdd(HH, IntervalDuration, DateAdd(D, (DateDiff(D, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration,  IntervalStartReferenceTime)))
                                WHEN 'Days' THEN (DateAdd(D, IntervalDuration, DateAdd(D, (DateDiff(D, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration,  IntervalStartReferenceTime)))
                                END
                             WHEN 'Months'THEN 
                                CASE IntervalDurationUnits
                                WHEN 'Hours' THEN (DateAdd(HH, IntervalDuration, DateAdd(MM, (DateDiff(MM, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration,  IntervalStartReferenceTime)))
                                WHEN 'Days' THEN (DateAdd(D, IntervalDuration, DateAdd(MM, (DateDiff(MM, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration,  IntervalStartReferenceTime)))
                                WHEN 'Months' THEN (DateAdd(MM, IntervalDuration, DateAdd(MM, (DateDiff(MM, IntervalStartReferenceTime, ActiveTimeNormalized ) / IntervalRepeatDuration) * IntervalRepeatDuration,  IntervalStartReferenceTime)))
                                END
                             END AS IntervalEnd
                            ,IntervalStartReferenceTime
                FROM    (
                            SELECT   IntervalType, SubIntervalType, IntervalDuration, IntervalDurationUnits, IntervalRepeatDuration, IntervalRepeatDurationUnits, IntervalStartReferenceTime,
                                     CASE IntervalRepeatDurationUnits
                                     WHEN 'Hours' THEN DATEADD(MILLISECOND, -1*(DATEPART(MILLISECOND, IntervalStartReferenceTime) + 3), DATEADD(SECOND, -1*DATEPART(SECOND, IntervalStartReferenceTime), DATEADD(MINUTE, -1*DATEPART(MINUTE, IntervalStartReferenceTime), @activeIntervalDateTime)))
                                     WHEN 'Days' THEN DATEADD(MILLISECOND, -1*(DATEPART(MILLISECOND, IntervalStartReferenceTime) + 3), DATEADD(SECOND, -1*DATEPART(SECOND, IntervalStartReferenceTime), DATEADD(MINUTE, -1*DATEPART(MINUTE, IntervalStartReferenceTime), DATEADD(HOUR, -1*DATEPART(HOUR, IntervalStartReferenceTime), @activeIntervalDateTime))))
                                     WHEN 'Months' THEN DATEADD(MILLISECOND, -1*(DATEPART(MILLISECOND, IntervalStartReferenceTime) + 3), DATEADD(SECOND, -1*DATEPART(SECOND, IntervalStartReferenceTime), DATEADD(MINUTE, -1*DATEPART(MINUTE, IntervalStartReferenceTime), DATEADD(HOUR, -1*DATEPART(HOUR, IntervalStartReferenceTime), DATEADD(DAY, -1*(DATEPART(DAY, IntervalStartReferenceTime) - 1), @activeIntervalDateTime)))))
                                     END AS ActiveTimeNormalized
                            FROM    dbo.IntervalConfiguration               
                        ) norm
                WHERE   IntervalType = @groupByInterval) interval
        WHERE   (@activeIntervalDateTime > IntervalStart) and (@activeIntervalDateTime <= IntervalEnd)
        ORDER BY IntervalStartReferenceTime DESC


        SET @intervalDurationSeconds = DATEDIFF(SECOND, @intervalStartTime, @intervalEndTime);

        IF @intervalStartTime >= @dateRangeStart AND @intervalEndTime <= @dateRangeEnd 
        BEGIN

            INSERT INTO @Intervals( 
                                         IntervalType
                                         ,SubIntervalType           
                                        ,IntervalStart          
                                        ,IntervalEnd            
                                        ,IntervalDurationSeconds                                    
                                      )
            VALUES(
                     @intervalName
                    ,@subIntervalType
                    ,@intervalStartTime
                    ,@intervalEndTime
                    ,@intervalDurationSeconds
                  )

        END

        SET @activeIntervalDateTime = DATEADD(MILLISECOND, 3, @intervalEndTime);

    END

    RETURN;
END

然而,这个功能变得越来越复杂,难以调试我也想消除在函数中使用While循环的需要。我的问题是,是否有更简单的方法来实现我的要求,是否可以消除对while循环的需求?

1 个答案:

答案 0 :(得分:0)

您可以通过使用计数表来简化查询并消除while循环,如下所示:

<UITabBarController>,
   | <UINavigationController>
   |    | <HomeViewController>
   | <UINavigationController>
   |    | <ChatViewController>
   | <UINavigationController>
   |    | <ProfileViewController>