想必你有一个日历表,如果你能够在周/月/年查询(如果不是,你应该创建一个)。使用WHERE
和GROUP BY
子句中的函数(包括日期数学)会使索引的使用无效,这通常会导致查询速度变慢。相反,最好指定范围开始/结束点,以便系统可以直接打索引。
无论如何,让我们添加时间到我们的日期数据!
好的,我们试图按天分组,对吗?
SELECT calendarDate as start
FROM CalendarTable
WHERE calendarDate >= :rangeStart
AND calendarDate < :rangeEnd
...好吧,好吧,可以让我们的开始,但查询时它是有帮助的结束,或者说真的,下一个组的开始,以及:
SELECT calendarDate as start, calendarDate + 1 DAY as end
FROM CalendarTable
WHERE calendarDate >= :rangeStart
AND calendarDate < :rangeEnd
这就是日期......除了我们还需要添加时间!
幸运的是,这是一个恒定值:
SELECT calendarDate as startDate, TIME('10:00:00') as startTime
calendarDate + 1 DAY as endDate, TIME('10:00:00') as endTime
FROM CalendarTable
WHERE calendarDate >= :rangeStart
AND calendarDate < :rangeEnd
我们可以在一个子查询或CTE包装这件事,但什么是用于连接的实际情况?
好了,问题正在检查或忽略的日期是参与时间:
task_end_date > startDate OR (task_end_date = startDate AND task_end_time >= startTime)
...和上限:
task_end_date < endDate OR (task_end_date = endDate AND task_end_time < endTime)
所以把他们放在一起看起来是像这样:
WITH QueryRange AS (SELECT calendarDate as startDate, CAST('10:00:00' as TIME) as startTime,
calendarDate + 1 DAY as endDate, CAST('10:00:00' as TIME) as endTime
FROM CalendarTable
WHERE calendarDate >= :startRange
AND calendarDate < :endRange)
SELECT QueryRange.startDate, QueryRange.startTime,
QueryRange.endDate, QueryRange.endTime,
TasksEnded.ended
FROM (SELECT QueryRange.startDate, COUNT(Tasks.task_name) as ended
FROM QueryRange
LEFT JOIN Tasks
ON (Tasks.task_end_date > QueryRange.startDate
OR (Tasks.task_end_date = QueryRange.startDate
AND Tasks.task_end_time >= QueryRange.startTime))
AND (Tasks.task_end_date < QueryRange.endDate
OR (Tasks.task_end_date = QueryRange.endDate
AND Tasks.task_end_time < QueryRange.endTime))
GROUP BY QueryRange.startDate) as TasksEnded
JOIN QueryRange
ON QueryRange.startDate = TasksEnded.startDate
ORDER BY QueryRange.startDate
Fiddle Example(忽略的细微变化上下工夫不同的RDBMS,原则是声音。)
作为一个方面说明,这是容易很多,如果你已经实际存储的日期/时间作为一个时间戳。假设你的日历文件仍然只在交易日期(应该),只是用它来构建完整的时间戳,而不是分开的栏位:
SELECT TIMESTAMP(calendarDate, '10:00:00') as rangeStart
TIMESTAMP(calendarDate + 1 DAY, '10:00:00') as rangeEnd
FROM CalendarTable
WHERE calendarDate >= :rangeStart
AND calendarDate < :rangeEnd
...然后让查询只使用一对检查。
LEFT JOIN Tasks
ON Tasks.task_end_stamp >= QueryRange.rangeStart
AND Tasks.task_end_stamp < QueryRange.rangeEnd
....和这将几乎肯定比与分离的字段所需的混合AND
/OR
更快。
所以是的,如果你首先从起始数据构造时间戳,你仍然可以查询和分组日期子字段。
它的db2(与AS400的ODBC连接) –
我对您的表格设计的直接反应是...不要单独存储日期和时间。这只会在以后引起很大的头痛(现在实际上)。 –
是的它是真的,但即使使用TIMESTAMP功能,我也无法找到选择时间周期的方法 –