SQL day1 时间 1 和 day 2 时间 2 之间的时间段选择
SQL period selection between time1 of day1 and time2 day2
我在 DB2 中有这样一个 table:
- 任务名称
- tast_end_date 日期格式
- task_end_time 时间格式
table 每天包含 100 条记录,我必须构建一个查询来计算从第 X 天的 10:00:00 到第 X+1 天的 09:59:59 结束的整个任务月
对我来说结果应该是这样的,例如:
- 期间 01.01.2017 时间 10:00:00 至 02.01.2017 时间 09:59:59,结束 25 个任务
- 期间 02.01.2017 时间 10:00:00 至 03.01.2017 时间 09:59:59,结束 25 个任务
- 期间 03.01.2017 时间 10:00:00 至 04.01.2017 时间 09:59:59,结束了 25 个任务
- 等等
所以不是简单的日期selection,我必须同时使用日期和时间的范围...crrrrazy
我正在使用 dbeaver select。感谢您的帮助!
就个人而言,我会构建时间戳,然后对其进行调整,使时间落在一个日历日内。那么就是统计日期组的问题了..
类似这样
with adj as (
select
timestamp(mydate, mytime)
- 9 hours - 59 minutes - 59 seconds - 1 microsecond
as ts
from mytable
)
select month(ts), count(*) as nbr_tasks
from adj
group by month(ts)
假设您有一个日历 table,如果您可以在 week/month/year 上查询(如果不能,您应该创建一个)。在 WHERE
和 GROUP BY
子句中使用函数(包括日期数学)会使索引的使用无效,这通常会导致查询速度变慢。相反,最好指定范围 start/end 点,以便系统可以直接命中索引。
无论如何,让我们为日期数据添加时间!
好的,我们尝试按天分组,对吗?
SELECT calendarDate as start
FROM CalendarTable
WHERE calendarDate >= :rangeStart
AND calendarDate < :rangeEnd
...好吧,好吧,这让我们开始了,但是当查询结束时,或者实际上,next 组的开始也是有帮助的:
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 上工作的微小变化,原则是合理的。)
作为旁注,如果您实际上将 date/time 存储为单个时间戳,这会容易得多。假设您的日历文件仍然只处理日期(它应该),只需使用它来构造完整的时间戳,而不是分隔的字段:
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 中有这样一个 table:
- 任务名称
- tast_end_date 日期格式
- task_end_time 时间格式
table 每天包含 100 条记录,我必须构建一个查询来计算从第 X 天的 10:00:00 到第 X+1 天的 09:59:59 结束的整个任务月
对我来说结果应该是这样的,例如:
- 期间 01.01.2017 时间 10:00:00 至 02.01.2017 时间 09:59:59,结束 25 个任务
- 期间 02.01.2017 时间 10:00:00 至 03.01.2017 时间 09:59:59,结束 25 个任务
- 期间 03.01.2017 时间 10:00:00 至 04.01.2017 时间 09:59:59,结束了 25 个任务
- 等等
所以不是简单的日期selection,我必须同时使用日期和时间的范围...crrrrazy
我正在使用 dbeaver select。感谢您的帮助!
就个人而言,我会构建时间戳,然后对其进行调整,使时间落在一个日历日内。那么就是统计日期组的问题了..
类似这样
with adj as (
select
timestamp(mydate, mytime)
- 9 hours - 59 minutes - 59 seconds - 1 microsecond
as ts
from mytable
)
select month(ts), count(*) as nbr_tasks
from adj
group by month(ts)
假设您有一个日历 table,如果您可以在 week/month/year 上查询(如果不能,您应该创建一个)。在 WHERE
和 GROUP BY
子句中使用函数(包括日期数学)会使索引的使用无效,这通常会导致查询速度变慢。相反,最好指定范围 start/end 点,以便系统可以直接命中索引。
无论如何,让我们为日期数据添加时间!
好的,我们尝试按天分组,对吗?
SELECT calendarDate as start
FROM CalendarTable
WHERE calendarDate >= :rangeStart
AND calendarDate < :rangeEnd
...好吧,好吧,这让我们开始了,但是当查询结束时,或者实际上,next 组的开始也是有帮助的:
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 上工作的微小变化,原则是合理的。)
作为旁注,如果您实际上将 date/time 存储为单个时间戳,这会容易得多。假设您的日历文件仍然只处理日期(它应该),只需使用它来构造完整的时间戳,而不是分隔的字段:
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
更快。
所以是的,如果您首先从起始数据构建时间戳,您仍然可以按日期子字段查询和分组。