生成可变时间步长

Generate variable time steps

大家好。

我正在尝试编写一个存储过程,以在几分钟内用时间簇填充维度 table。例如集群 = 30:00:00-00:29、00:30-00:59、01:00-01:29 等等。

到目前为止,我想不出更好的解决方案,只能按照提供的步骤循环超过 24 小时,当时间跳过 00:00 并重新开始时,存在无限循环的危险。

寻找可能的解决方案,我找到了一个优雅的解决方案:但没有弄清楚如何使其适应不同的时间步长。

*编辑:由于我正在处理 Azure Synapse SQL 池,因此无法使用序列生成和递归 CTE。

你可以使用递归cte

; with rcte as
(
    select  tm = cast('00:00' as time(0))    -- start time
    union all
    select  tm = dateadd(minute, 30, tm)     -- 30 mins increment
    from    rcte
    where   tm  < '12:00'                    -- end time
)
select  *
from    rcte

计数table方法

declare @st time(0) = '00:00',
        @en time(0) = '03:30';
 
with tally (n) as
(
    -- 1000 rows
    select row_number() over(order by (select null)) - 1
    from (values (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) a(n)
    cross join (values (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) b(n)
    cross join (values (0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) c(n)
)
SELECT  tm = dateadd(minute, n * 30, @st)
FROM    tally
where   n   <= datediff(minute, @st, @en) / 30

感谢@Squirrel 在 Tally 表上指出作为循环的优雅且高效的替代品。我提出了以下解决方案:

declare @st time(0) = '00:00',
        @en time(0) = '23:59',
        @incr tinyint = 7; --variable increment in minutes
 
with tally (n) as
(
  SELECT TOP 1439 --max amount of minutes from 00:00 to 23:59
      ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS [N]
  FROM dbo.syscolumns tb1
      CROSS JOIN dbo.syscolumns tb2
)
SELECT  
          dateadd(minute, (n -1 ) * @incr, @st) as StartTime
        , CASE 
            WHEN dateadd(minute, (n - 1) * @incr, @st) < dateadd(minute, n * @incr, @st) THEN dateadd(minute, n * @incr, @st)
            ELSE CONVERT(time(0), '23:59:59')   
          END AS EndTime --Preventing time to jump over 00:00 again 
FROM    tally
where   n-1   <= datediff(minute, @st, @en) / @incr

试试这个:

DECLARE @TimeCluster    TABLE 
    (
            TimeBegin   time
        ,   TimeEnd     time
    )
;
DECLARE @TimeBegin      time    =   '00:00'
    ,   @TimeEnd        time    =   '00:29'
    ,   @TimeLapseMins  int     =   30
;
WHILE   @TimeEnd <> '23:59'
    BEGIN
        INSERT INTO @TimeCluster    VALUES  (@TimeBegin, @TimeEnd)

        SET @TimeBegin  =   DATEADD(MINUTE, @TimeLapseMins, @TimeBegin  )
        SET @TimeEnd    =   DATEADD(MINUTE, @TimeLapseMins, @TimeEnd    )
        ;
    END
;

SELECT * FROM @TimeCluster