【问题标题】:Case statement with DATEADD for over 24 hour calculation使用 DATEADD 进行超过 24 小时计算的案例语句
【发布时间】:2018-12-15 07:33:22
【问题描述】:

我正在为一个项目做噩梦。我正在使用 SQL 从我们的排班系统中提取信息。无论出于何种原因,排班系统都允许将随叫随到的班次创建为例如“+0000 - 0700”。 24:00 - 31:00 返回。

在测试 SQL 时,我花了好几天的时间才确定这个事实是造成我痛苦的原因。一旦例程遇到这些转变之一,它就会出现“超出范围错误”,这更有意义,现在我发现了问题!

但是,由于我需要解决代码中的怪异问题,因此并不像告诉某人改变他们的做法那么简单,这样 24 小时内的轮班就不再存在了,所以我希望将这些问题时间手动解释为我可以做到的事情一起工作。

以下行对我来说很有意义,但也因超出范围错误而失败:

SELECT
    RRP.shiftdate,
    CASE 
       WHEN RDS.SHIFTSTART > ‘23:59:59’ 
          THEN DATEADD(HOUR, -24, RDS.SHIFTSTART)
          ELSE RDS.SHIFTSTART
    END AS CLEANSED_SHIFTSTART
...

但是,这会崩溃并显示此错误:

将 varchar 数据类型转换为日期时间数据类型导致值超出范围

函数的哪一部分在抱怨?

CASE WHEN RDS.SHIFTSTART > ‘23:59:59’ THEN ‘ABOVE 24H’

这很好用,但我无法解决 DATEADD 的问题,因为我在代码的其他地方成功使用了它。

【问题讨论】:

  • 你能在模式中添加一列吗?你有数据库的控制权吗?

标签: sql case dateadd


【解决方案1】:

我试图删除这个答案,但它没有让我接受,因为它已被接受。所以我只是在编辑它以说明为什么它不应使用以及我的错误是什么,我希望这也有用:

我建议使用替换,它的工作原理是值,而不是位置,所以如果我有一个时间是 '28:59:28',它实际上会更改为 04:59:4

我错误建议的解决方案是:

考虑到您使用的是字符串,这应该可以解决问题:

SELECT CASE WHEN RDS.SHIFTSTART > '23:59:59' THEN 
                    CASE WHEN (CAST(LEFT(RDS.SHIFTSTART,2) AS INT)%24) < 10
                         THEN '0'+ REPLACE(RDS.SHIFTSTART,LEFT(RDS.SHIFTSTART,2),(CAST(LEFT(RDS.SHIFTSTART,2) AS INT)%24))
                    ELSE REPLACE(RDS.SHIFTSTART,LEFT(RDS.SHIFTSTART,2), (CAST(LEFT(RDS.SHIFTSTART,2) AS INT)%24) )
                    END
       ELSE RDS.SHIFTSTART
       END AS Cleansed_ShiftStart

这将适用于任何时间,因此如果您的轮班时间开始于:“49:34:54”,则应该是“01:34:54”

但如果班次最多为 +7,那么您可以简单地这样做:

    SELECT CASE WHEN RDS.SHIFTSTART > '23:59:59' 
                THEN '0'+ REPLACE(RDS.SHIFTSTART,LEFT(RDS.SHIFTSTART,2),(CAST(LEFT(RDS.SHIFTSTART,2) AS INT)%24))                     
                ELSE RDS.SHIFTSTART
           END AS Cleansed_ShiftStart

【讨论】:

  • 谢谢,该字符串仅用于显示,因此(复杂)一些维持日期/时间格式的总和是幸运的,不需要。我肯定是想多了这个。感谢您的帮助
  • 其实你应该使用下面的答案。我的回答有误。部分原因是我不知道使用 stuff() 的选项,我仍然是初学者 :) 有一个我没有想到的大错误。我正在使用替换,它按值而不是位置起作用,所以如果我有一个时间是“28:59:28”,它实际上会更改为 04:59:4。很抱歉这个错误,我希望你没有因此浪费任何时间。
【解决方案2】:

假设您的 shiftstart 值始终以两位数开头,您可以将前两位数替换为数字模数 24:

select stuff(rds.shiftstart, 1, 2,
             left(rds.shiftstart, 2) % 24
            ) as cleansed_shiftstart

这不会将值转换为时间;如果你想要它作为一个时间,那么转换将是安全的。

不喜欢隐式转换,我可能会明确写:

select stuff(rds.shiftstart, 1, 2,
             try_convert(int, left(rds.shiftstart, 2)) % 24
            ) as cleansed_shiftstart

【讨论】:

    【解决方案3】:

    这是否有助于为您指明正确的方向?

    我在下面使用Common Table Expressions 来虚拟化一些数据。

    此版本可以处理范围超过“24:00:00”的相当奇怪的“时间”值以及没有前导零的“时间”值(例如“7:00:00”)。

    WITH s1
    as
    (
    SELECT '31:50:12' as SHIFTSTART
           ,CAST(LEFT('31:50:12', CHARINDEX(':','31:50:12') - 1) as int) as my_hours_parsed
           ,SUBSTRING('31:50:12', CHARINDEX(':','31:50:12'), 10) as my_min_sec
    UNION
    SELECT '21:15:23' as SHIFTSTART
           ,CAST(LEFT('21:15:23', CHARINDEX(':','21:15:23') - 1) as int) as my_hours_parsed
           ,SUBSTRING('21:15:23', CHARINDEX(':','21:15:23'), 10) as my_min_sec
    UNION
    SELECT '7:00:00' as SHIFTSTART
           ,CAST(LEFT('7:00:00', CHARINDEX(':','7:00:00') - 1) as int) as my_hours_parsed
           ,SUBSTRING('7:00:00', CHARINDEX(':','7:00:00'), 10) as my_min_sec
    UNION
    SELECT '49:00:00' as SHIFTSTART
           ,CAST(LEFT('49:00:00', CHARINDEX(':','49:00:00') - 1) as int) as my_hours_parsed
           ,SUBSTRING('49:00:00', CHARINDEX(':','49:00:00'), 10) as my_min_sec
    UNION
    SELECT '99:23:00' as SHIFTSTART
           ,CAST(LEFT('99:23:00', CHARINDEX(':','99:23:00') - 1) as int) as my_hours_parsed
           ,SUBSTRING('99:23:00', CHARINDEX(':','99:23:00'), 10) as my_min_sec
    UNION
    SELECT '157:23:00' as SHIFTSTART
           ,CAST(LEFT('157:23:00', CHARINDEX(':','157:23:00') - 1) as int) as my_hours_parsed
           ,SUBSTRING('157:23:00', CHARINDEX(':','157:23:00'), 10) as my_min_sec           
    
    )
    SELECT s1.SHIFTSTART
          ,s1.my_hours_parsed
          ,s1.my_min_sec
          ,CASE WHEN s1.my_hours_parsed > 24 
                THEN 'Houston, we have a problem' 
                ELSE 'Works for me'
                END as SHIFTSTART_profile
          ,CAST(s1.my_hours_parsed - 24*(s1.my_hours_parsed/24) AS varchar(2)) + s1.my_min_sec as my_time_mod             
    FROM s1;
    

    这是结果...

        SHIFTSTART  my_hours_parsed my_min_sec  SHIFTSTART_profile              my_time_mod
    1   157:23:00   157             :23:00      Houston, we have a problem      13:23:00
    2   21:15:23    21              :15:23      Works for me                    21:15:23
    3   31:50:12    31              :50:12      Houston, we have a problem      7:50:12
    4   49:00:00    49              :00:00      Houston, we have a problem      1:00:00
    5   7:00:00     7               :00:00      Works for me                    7:00:00
    6   99:23:00    99              :23:00      Houston, we have a problem      3:23:00
    

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-09-24
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-19
      • 1970-01-01
      相关资源
      最近更新 更多