【问题标题】:SQL Server find nearest shift start (time) to a dateSQL Server 查找距某个日期最近的班次开始(时间)
【发布时间】:2017-04-21 13:50:23
【问题描述】:

我需要查找自上次轮班开始以来已更改的记录。 班次从 07:00(早上)、15:00(下午)和 23:00(晚上)开始。

例如。现在是 17 点 15 分,所以我在下午班。现在我想查找自上一班开始以来已更改的工作相关记录。所以我需要前一天 15:00 的开始时间。即 24 小时前 + 当前班次的时间。

我需要一个可以作为 where 子句的一部分实施的解决方案。

基本上,我会尝试找到一个班次的最后开始时间(7、15 或 23 小时),然后从该日期减去另外 24 小时。并让查询一直运行到当前时间。

select * from workorder
where changedate >= getDate() - 24h - time_in_shift

select * from workorder
where changedate >= last_shift_start - 24h

说实话,我还没有找到好的策略。起初,我试图用 case 语句找到正确的班次,并用它来进行正确的计算。但我认为这不是最好的方法。

select getDate() as now,
case
   when datepart(hh, getDate())-23 >= 0 then 'night'
   when datepart(hh, getDate())-15 >= 0 then 'afternoon'
   when datepart(hh, getDate())-7 >= 0 then 'morning'
   else 'night'
end as shift; 

这是一些示例数据

id changedate
1 '2017-04-20 01:00:00'
2 '2017-04-20 02:00:00'
3 '2017-04-20 08:00:00'
4 '2017-04-20 09:00:00'
5 '2017-04-20 14:00:00'
6 '2017-04-20 16:00:00'
7 '2017-04-20 17:00:00'
8 '2017-04-20 22:00:00'
9 '2017-04-20 23:00:00'
10 '2017-04-20 23:30:00'
11 '2017-04-21 01:10:00'
12 '2017-04-21 02:10:00'
13 '2017-04-21 08:10:00'
14 '2017-04-21 10:10:00'
15 '2017-04-21 16:10:00'
16 '2017-04-21 16:20:00'

假设现在是 2017-04-21 17:00:00。所以我在下午值班。 这意味着我想要自上次开始以来已更改的所有记录。因此从 2017-04-20 15:00:00 开始。这是除前 5 条以外的所有记录。

【问题讨论】:

  • 请发布一些示例数据和预期的输出。
  • 您是否计划硬编码轮班开始时间并回顾 24 小时?
  • 是的,这是一个可配置的结果查询,所以很容易访问,而且不太可能改变
  • 明确一点 - 如果当前是 02:00,我们想要两天前的 23:00 之后的所有内容,对吗?
  • @Damien_The_Unbeliever:哎呀,你是对的。所以我的回答有问题。

标签: sql sql-server tsql date datetime


【解决方案1】:

首先是一个班次表(只有一列)。当然,您可以即时生成它,但为什么不在您的数据库中呢?

换档开始 07:00 15:00 23:00

要获得当前班次,您可以执行以下操作:

select
  coaleasce
  (
    max(case when shiftstart < cast(getdate() as time) then shiftstart end),
    max(shiftstart)
  )
from shift;

添加昨天以获得昨天的 shiftstart:

dateadd(day, -1, cast(getdate() as date)) + <above time>

更新:正如 Damien_The_Unbeliever 正确指出的那样:

如果现在是 02:00,我们想要两天前 23:00 之后的所有内容

所以我们必须根据时间减去一天或两天。


调整后的完整查询:

select *
from workorder
where changedate >=
(
  select
    coaleasce
    (
      dateadd(day, -1, cast(getdate() as date)) + 
      max(case when shiftstart < cast(getdate() as time) then shiftstart end),
      dateadd(day, -2, cast(getdate() as date)) + 
      max(shiftstart)
    )
  from shift
);

【讨论】:

    【解决方案2】:

    如果您使用的是 SQL Server 2012,则可以使用 case 语句构建您的 WHERE 子句:

    select  *
    from    workorder
    where   changedate >= case
                when datepart(hh, getDate()) >= 23
                  then smalldatetimefromparts(year(dateadd(day, -1, cast(getdate() as date))),
                                              month(dateadd(day, -1, cast(getdate() as date))),
                                              day(dateadd(day, -1, cast(getdate() as date))),
                                              23, 00)
                when datepart(hh, getDate()) < 7
                  then smalldatetimefromparts(year(dateadd(day, -2, cast(getdate() as date))),
                                              month(dateadd(day, -2, cast(getdate() as date))),
                                              day(dateadd(day, -2, cast(getdate() as date))),
                                              23, 00)
                when datepart(hh, getDate()) between 15 and 22
                  then smalldatetimefromparts(year(dateadd(day, -1, cast(getdate() as date))),
                                              month(dateadd(day, -1, cast(getdate() as date))),
                                              day(dateadd(day, -1, cast(getdate() as date))),
                                              15, 00)
                else smalldatetimefromparts(year(dateadd(day, -1, cast(getdate() as date))),
                                            month(dateadd(day, -1, cast(getdate() as date))),
                                            day(dateadd(day, -1, cast(getdate() as date))),
                                            7, 00)
            end;
    

    如果您使用的是旧版本的 SQL Server,同样可以通过几个显式转换替换 smalldatetimefromparts 来完成;你可以在this answer看到它的解释

    【讨论】:

    • 使用getDate() - 1 构建日期时间在一个月的第一天失败。
    猜你喜欢
    • 1970-01-01
    • 2012-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多