我正在编写一份报告查询,我需要选择该时间段是否属于" Day"或者"晚上"。我想选择的表格如下:
DAYNIGHT_TABLE
:
Description | StartTime | EndTime
Night | 18:00:00.0000000 | 06:00:00.0000000
Day | 06:00:00.0000000 | 18:00:00.0000000
对于不同的客户,这可能会被分解为更小的时间段,但作为起点,我只需要根据我从另一个表中检索的日期时间选择Day
或Night
。
如果我做这样的话,那我就得到一天:
SELECT Description
FROM Table s
WHERE convert(TIME,myTable.MyDateTime) >= s.StartTime
AND convert(TIME,myTable.MyDateTime) < s.StartTime
我觉得我在这里遗漏了一些明显的东西但是如何根据myTable.MyDateTime的已知时间从DAYNIGHT_TABLE
检索日/夜描述?
答案 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)))