0

我正在尝试通过 SQL 返回具有给定间隔的开始时间和结束时间之间的所有有效时间段,但是我的心理障碍很大。下面是一些带有一些变量的示例代码,然后是一个存储每个值的表。变量使用 INT,因为最终将存储值的数据类型是 INT,并且无法更改

DECLARE @StartTime INT = 900
DECLARE @EndTime INT = 2000
DECLARE @CurrentTime INT = 900
DECLARE @Interval INT = 15

DECLARE @Times TABLE
(
    [Time] INT
)

WHILE (@CurrentTime <= @EndTime)
BEGIN
    INSERT INTO @Times VALUES (@CurrentTime)

    SET @CurrentTime = @CurrentTime + @Interval
END

当上述运行时,它会填充,但给我无效值。返回值:

900
915
930
945
960
975
etc.

期望的结果是:

900
915
930
945
1000
1015
1030
etc.

有没有办法做到这一点,通过除以当前值并期待一个余数,或者一种简单的方法来实现预期的结果?

谢谢

4

2 回答 2

2

试试这个

DECLARE @StartTime INT = 900
DECLARE @EndTime INT = 2000
DECLARE @CurrentTime INT = 900
DECLARE @Interval INT = 15

DECLARE @Times TABLE
(
    [Time] INT
)

WHILE (@CurrentTime <= @EndTime)
BEGIN
    INSERT INTO @Times VALUES (@CurrentTime)

    SET @CurrentTime = @CurrentTime + @Interval

    IF(RIGHT(@CurrentTime,2) = 60)
        SET @CurrentTime = @CurrentTime + 40

END

SELECT * FROM @Times
于 2013-08-14T08:35:39.273 回答
1

这有点复杂,但与上述答案有几个不同之处:它可以跨越午夜,处理不是 60 的因数的间隔(尝试上面的间隔为 7),并使用递归 CTE 生成数字而不是 WHILE 循环。

它对 INT 数据类型感到遗憾,具有 TSQL 的 TIME 数据类型的所有好处。您可以取消辅助功能。

MAXRECURSION 选项有时会出现问题,因为您不能在视图中使用它……调用语句必须指定它。为了解决这个问题,将它包装在一个多语句表值函数中。 看到这个帖子

CREATE FUNCTION dbo.ConvertIntToTime (@TimeAsInt INT)
RETURNS TIME
BEGIN

    DECLARE @TimeString VARCHAR(4) = RIGHT(REPLICATE('0',4) + CAST(@TimeAsInt AS VARCHAR(4)),4);
    RETURN PARSE(LEFT(@TimeString,2) + ':' + RIGHT(@TimeString,2) AS TIME);

END;
GO

CREATE FUNCTION dbo.ConvertTimeToInt (@Time TIME)
RETURNS INT
BEGIN

    DECLARE @TimeString VARCHAR(5) = CONVERT(VARCHAR(5), @Time, 108);
    RETURN PARSE(LEFT(@TimeString,2) + RIGHT(@TimeString,2) AS INT); 

END;
GO



DECLARE @CurrentTime AS INT = 900;
DECLARE @EndTime AS INT = 1700;
DECLARE @Interval AS INT = 10;

DECLARE @CurrentTimeAsTime TIME = dbo.ConvertIntToTime(@CurrentTime);
DECLARE @EndTimeAsTime TIME = dbo.ConvertIntToTime(@EndTime);

WITH CTEGenerateTimes AS
(

    SELECT  @CurrentTimeAsTime Time

    UNION ALL

    SELECT DATEADD(MINUTE, @Interval, Time) AS TIME
    FROM CTEGenerateTimes
    WHERE   (@EndTimeAsTime >= @CurrentTimeAsTime AND DATEADD(MINUTE, @Interval, Time) <= @EndTimeAsTime AND DATEADD(MINUTE, @Interval, Time) <> CAST('00:00' AS TIME)) --Range doesn't cross midnight
            OR (@EndTimeAsTime < @CurrentTimeAsTime AND DATEADD(MINUTE, @Interval, Time) > @CurrentTimeAsTime AND DATEADD(MINUTE, @Interval, Time) <= CAST('23:59:59' AS TIME))  --Range crosses midnight, portion before midnight
            OR (@EndTimeAsTime < @CurrentTimeAsTime AND DATEADD(MINUTE, @Interval, Time) <= @CurrentTimeAsTime AND DATEADD(MINUTE, @Interval, Time) <= @EndTimeAsTime)

)

SELECT dbo.ConvertTimeToInt(t.Time) Time
FROM CTEGenerateTimes t
OPTION (MAXRECURSION 1441)
于 2013-08-14T11:27:07.847 回答