生成15分钟的日期间隔并加入匹配的行

时间:2018-11-26 14:20:48

标签: sql sql-server tsql datetime

我想做的是根据行中的日期范围获取15分钟的间隔并将其插入到另一个表中。

鉴于以下代码为我提供了目标范围内的日期范围:

DECLARE @Table1 TABLE (ID INT IDENTITY(0,1), TIMEVALUE DATETIME, TIMEVALUE2 DATETIME);
DECLARE @start DATETIME2(7) = '2018-01-04 10:55:00'
DECLARE @end DATETIME2(7) = '2018-01-05 03:55:00'
SELECT  @start = dateadd(minute, datediff(minute,0,@start) / 15 * 15, 0);

WITH CTE_DT AS 
(
    SELECT @start AS DT
    UNION ALL
    SELECT DATEADD(MINUTE,15,DT) FROM CTE_DT
    WHERE DT< @end
)
INSERT INTO @Table1
SELECT DT, DATEADD(minute,14,dt) FROM CTE_DT
OPTION (MAXRECURSION 0);

SELECT * FROM @Table1    

结果:

ID  TIMEVALUE               TIMEVALUE2
0   2018-01-04 10:45:00.000 2018-01-04 10:59:00.000
1   2018-01-04 11:00:00.000 2018-01-04 11:14:00.000
2   2018-01-04 11:15:00.000 2018-01-04 11:29:00.000
3   2018-01-04 11:30:00.000 2018-01-04 11:44:00.000
4   2018-01-04 11:45:00.000 2018-01-04 11:59:00.000
5   2018-01-04 12:00:00.000 2018-01-04 12:14:00.000
6   2018-01-04 12:15:00.000 2018-01-04 12:29:00.000
7   2018-01-04 12:30:00.000 2018-01-04 12:44:00.000
8   2018-01-04 12:45:00.000 2018-01-04 12:59:00.000
..
..

我要完成的是从记录源中在i上方应用相同的逻辑。

所以,如果我的SourceData是

Col1    Col2    StartDate           EndDate
AA      AA      2018-01-01 13:25    2018-01-02 13:00
AA      BB      2018-01-02 13:25    2018-01-03 13:00

因此,对于查询,无论如何都使用start和endate来仅通过查询来产生此结果

Col1    Col2    TIMEVALUE       TIMEVALUE2
AA      AA  2018-01-01 13:15:00 2018-01-01 13:29:00
AA      AA  2018-01-01 13:30:00 2018-01-01 13:44:00
AA      AA  2018-01-01 13:45:00 2018-01-01 13:59:00
...
...
AA      AA  2018-01-02 12:30:00 2018-01-02 12:44:00
AA      AA  2018-01-02 12:45:00 2018-01-02 12:59:00
AA      AA  2018-01-02 13:00:00 2018-01-02 13:14:00
AA      BB  2018-01-02 13:15:00 2018-01-02 13:29:00
AA      BB  2018-01-02 13:30:00 2018-01-02 13:44:00
AA      BB  2018-01-02 13:45:00 2018-01-02 13:59:00
...
...
AA      BB  2018-01-03 12:30:00 2018-01-03 12:44:00
AA      BB  2018-01-03 12:45:00 2018-01-03 12:59:00
AA      BB  2018-01-03 13:00:00 2018-01-03 13:14:00

如果可以的话,我想避免使用游标。通过将必需的列与select语句一起传递,我设法使它与用户定义函数一起使用。我希望我能避免使用它。

3 个答案:

答案 0 :(得分:0)

更改第一个查询的结尾,以代替

SELECT * FROM @Table1  

它说:

SELECT * FROM @Table1 d 
INNER JOIN SourceData sd 
ON NOT(d.timevalue2 < sd.startdate OR d.timevalue1 > sd.enddate)

考虑采用第一个查询来生成日期,现在就运行直到2030年,然后将日期插入到实际表中。保持查询无处不在,以便可以在约11年内再次使用该查询,以便在日历表中添加更多行

答案 1 :(得分:0)

我将使用虚拟理货表格来生成日期,而不是使用rCTE(这是RBAR的一种形式)

--; is a statement terminator, not a "beginninator". It goes at the end, for the start.
WITH N AS(
    SELECT NULL AS N
    FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL)) N(N)),
Tally AS (
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) -1 AS I
    FROM N N1 --10
         CROSS JOIN N N2 --100
         CROSS JOIN N N3 --1000
         CROSS JOIN N N4 --10000
    )
SELECT DATEADD(MINUTE,15*I,@Start)
FROM Tally
WHERE DATEADD(MINUTE,15*I,@Start) < @End;

如果要为一列组合生成15分钟的间隔,则可以再执行CROSS JOIN。例如:

--Assume CTEs are already declared
SELECT V.Col1, V.Col2,
       DATEADD(MINUTE,15*T.I,@Start)
FROM Tally T
     CROSS JOIN (VALUES('AA','AA'),('AA','BB')) V(Col1, Col2) --This could be a CROSS APPLY to a DISTINCT, or similar is you wish
WHERE DATEADD(MINUTE,15*T.I,@Start) < @End;

答案 2 :(得分:0)

我不同意将结束时间设为14、29、44和59。它不会匹配诸如00:14:59.9999999之类的值。话虽如此,这是您需要的加入条件:

SELECT *
FROM @Table1
INNER JOIN yourdata ON TIMEVALUE2 >= StartDate AND EndDate >= TIMEVALUE

DEMO on DB Fiddle

将以上内容转换为专有结束日期(15、30、45和00)非常简单。只需将>=更改为>

Demo on DB Fiddle