选择12小时时间段SQL Server 2008的描述

时间:2015-06-17 05:30:33

标签: sql sql-server sql-server-2008

我正在编写一份报告查询,我需要选择该时间段是否属于" Day"或者"晚上"。我想选择的表格如下:

DAYNIGHT_TABLE

Description | StartTime        | EndTime
Night       | 18:00:00.0000000 | 06:00:00.0000000
Day         | 06:00:00.0000000 | 18:00:00.0000000

对于不同的客户,这可能会被分解为更小的时间段,但作为起点,我只需要根据我从另一个表中检索的日期时间选择DayNight

如果我做这样的话,那我就得到一天:

SELECT Description
FROM Table s
WHERE convert(TIME,myTable.MyDateTime) >= s.StartTime
  AND convert(TIME,myTable.MyDateTime) < s.StartTime

我觉得我在这里遗漏了一些明显的东西但是如何根据myTable.MyDateTime的已知时间从DAYNIGHT_TABLE检索日/夜描述?

2 个答案:

答案 0 :(得分:3)

如果您根本无法触摸DAYNIGHT_TABLE表,请阅读以下内容。

由于您只需要标签“Day”或“Night”,我建议您更改DAYNIGHT_TABLE表并在其中再添加一行,以便任何行中的任何时间都不会超过午夜。它使查询更简单有效:

DAYNIGHT_TABLE:

Description | StartTime        | EndTime
Night       | 18:00:00.0000000 | 00:00:00.0000000
Night       | 00:00:00.0000000 | 06:00:00.0000000
Day         | 06:00:00.0000000 | 18:00:00.0000000

此外,请确保始终如一地假设间隔的哪一端是包含的,哪个是独占的。我假设它是[StartTime; EndTime),即StartTime包含且EndTime独占。

StartTime DESC上添加一个索引,其中包含Description列。它并不是真的需要,DAYNIGHT_TABLE中的行数很少,你可能不会注意到任何差异,但仍然存在。

现在,如果您有一个包含myTable列的表MyDateTime,并希望从DAYNIGHT_TABLE获得正确的匹配说明,请使用以下内容:

SELECT
    myTable.MyDateTime
    ,CA.Description
FROM
    myTable
    CROSS APPLY
    (
        SELECT TOP(1) DAYNIGHT_TABLE.Description
        FROM DAYNIGHT_TABLE
        WHERE DAYNIGHT_TABLE.StartTime <= CAST(myTable.MyDateTime AS time)
        ORDER BY DAYNIGHT_TABLE.StartTime DESC
    ) AS CA

myTable CROSS APPLY中的每一行都会找到一个匹配的描述。

确保DAYNIGHT_TABLE中的时间间隔涵盖所有24小时无间隙。

请注意,该查询根本不使用EndTime,因为它假设表格中的时间间隔为24小时。因此,您可以从表中删除此列,它将如下所示:

Description | StartTime        
Night       | 00:00:00.0000000 
Day         | 06:00:00.0000000 
Night       | 18:00:00.0000000 

使用具有这两列的此类表,唯一需要的索引只是StartTime上唯一的群集主键。

如果您根本无法触摸DAYNIGHT_TABLE表,但如果您仍然可以保证表(a)中的间隔不重叠,(b)没有间隙,(c)覆盖整整24小时,然后在查询中将有一个额外的步骤。

如果上面列出的所有条件都成立,那么最​​多只能有一行跨越午夜,这意味着它的StartTime大于其EndTime。这就是我们如何找到它并照顾它的方法。我再次假设StartTime具有包容性,EndTime是独占的。

DECLARE @DAYNIGHT_TABLE TABLE(Description varchar(50), StartTime time, EndTime time);

INSERT INTO @DAYNIGHT_TABLE(Description, StartTime, EndTime) VALUES 
('Night', '18:00:00', '06:00:00'),
('Day', '06:00:00', '18:00:00');

DECLARE @myTable TABLE(MyDateTime datetime);
INSERT INTO @myTable (MyDateTime) VALUES
('2015-01-01 00:00:00'),
('2015-01-01 02:02:02'),
('2015-01-01 06:00:00'),
('2015-01-01 12:02:02'),
('2015-01-01 18:00:00'),
('2015-01-01 22:02:02');

WITH
CTE_TimeIntervals
AS
(
    SELECT
        Description
        ,StartTime
    FROM @DAYNIGHT_TABLE AS DAYNIGHT_TABLE

    UNION ALL

    SELECT
        Description
        ,CAST('00:00:00' AS time) AS StartTime
    FROM @DAYNIGHT_TABLE AS DAYNIGHT_TABLE
    WHERE StartTime >= EndTime
)
SELECT
    myTable.MyDateTime
    ,CA.Description
FROM
    @myTable AS myTable
    CROSS APPLY
    (
        SELECT TOP(1) CTE_TimeIntervals.Description
        FROM CTE_TimeIntervals
        WHERE CTE_TimeIntervals.StartTime <= CAST(myTable.MyDateTime AS time)
        ORDER BY CTE_TimeIntervals.StartTime DESC
    ) AS CA

结果集

MyDateTime                 Description
2015-01-01 00:00:00.000    Night
2015-01-01 02:02:02.000    Night
2015-01-01 06:00:00.000    Day
2015-01-01 12:02:02.000    Day
2015-01-01 18:00:00.000    Night
2015-01-01 22:02:02.000    Night

答案 1 :(得分:1)

你需要这样的东西,用不同的值测试它:

http://www.sqlfiddle.com/#!3/d6328/1/0

select s1.myDate, t.Descr
from s s1
inner join DAYNIGHT_TABLE t on datepart(hour, s1.myDate) >= datepart(hour, t.StartTime) 
AND datepart(hour, s1.myDate) < datepart(hour, t.EndTime) 
OR ((t.EndTime < t.StartTime) AND ( datepart(hour, s1.myDate) >= datepart(hour, t.StartTime)) AND datepart(hour, s1.mydate) < (datepart(hour, t.StartTime) + datepart(hour, t.EndTime)))