超过 24 小时计算的带有 DATEADD 的案例语句
Case statement with DATEADD for over 24 hour calculation
我正在为工作中的项目做噩梦。我正在使用 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
...
但是,这会崩溃并显示此错误:
Conversion of a varchar data type to a date time data type resulted in an out of range value
函数的哪一部分在抱怨?
CASE WHEN RDS.SHIFTSTART > ‘23:59:59’ THEN ‘ABOVE 24H’
这很好用,但我无法解决 DATEADD
的问题,因为我在我的代码中的其他地方成功地使用了它。
我试图删除这个答案,但它不允许我删除,因为它已被接受。所以我只是编辑它来说明为什么它 不应该被使用 以及我的 错误是什么 ,我希望这也有用:
我建议使用替换,它根据值而不是位置起作用,所以如果我的时间是“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
这是否有助于为您指明正确的方向?
我使用下面的 Common Table Expressions 来模拟一些数据。
此版本可以处理相当奇怪的 "time" 范围超过“24:00:00”的值以及 "time" 没有前导零的值(“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
希望对您有所帮助
假设您的 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
我正在为工作中的项目做噩梦。我正在使用 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
...
但是,这会崩溃并显示此错误:
Conversion of a varchar data type to a date time data type resulted in an out of range value
函数的哪一部分在抱怨?
CASE WHEN RDS.SHIFTSTART > ‘23:59:59’ THEN ‘ABOVE 24H’
这很好用,但我无法解决 DATEADD
的问题,因为我在我的代码中的其他地方成功地使用了它。
我试图删除这个答案,但它不允许我删除,因为它已被接受。所以我只是编辑它来说明为什么它 不应该被使用 以及我的 错误是什么 ,我希望这也有用:
我建议使用替换,它根据值而不是位置起作用,所以如果我的时间是“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
这是否有助于为您指明正确的方向?
我使用下面的 Common Table Expressions 来模拟一些数据。
此版本可以处理相当奇怪的 "time" 范围超过“24:00:00”的值以及 "time" 没有前导零的值(“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
希望对您有所帮助
假设您的 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