【问题标题】:SQL Convert & Cast Nvarchar Time to a decimalSQL 将 Nvarchar 时间转换为小数
【发布时间】:2022-01-11 21:58:16
【问题描述】:

我正在处理旧数据库,需要将信息从一个数据库解析到另一个数据库,将其解析到新数据库很容易,但首先我需要创建查询以在旧 SQL Server 中转换和转换以下内容数据库:

WorkedHours(NVARCHAR(10)) 是文本格式 07:30

我需要将其转换为小数,即 7.5

我已经四处寻找这个问题的答案,但找不到任何有效的方法,所以我想我会把它放在那里看看你们是否有任何想法。

编辑 - 我应该问的是。尝试将时间转换为小数并将时间转换为小数时,导致从值为 0 的字符转换为 int 时出错的原因是什么?

【问题讨论】:

  • 你的十进制值的精度和小数位数是多少?
  • 基本上是除法吧?将冒号后面的所有内容除以 60。只需将分子转换为适当的小数位数。
  • 超过 1 个示例会有所帮助。值是否始终采用hh:mm 格式?值是否可以超过 99 小时?
  • @Larnu ,NVarchar 字段的小时数为 hh:mm,最大小时数为 24
  • 您的值是实际的“时间”还是“持续时间”?仔细考虑区别以及您打算如何使用此值。

标签: sql sql-server tsql


【解决方案1】:
DATEDIFF(
  MINUTE,
  0,
  CAST('07:30' AS TIME)
)
/
60.0

仅适用于'23:59'

编辑:

根据其他地方的评论,你有一些“坏”的价值观。

这可能会找到他们...

SELECT
  *
FROM
  yourTable
WHERE
  TRY_CONVERT(TIME, worked_hours) IS NULL

因此,这是我表达的更安全版本....

DATEDIFF(
  MINUTE,
  0,
  TRY_CONVERT(TIME, worked_hours)
)
/
60.0

(对于解析失败的值返回 NULL。)

【讨论】:

  • 是的,当您指定 7:30 时,这很好,只要我添加列名,我就会得到错误转换失败到字符串的日期/时间
  • 然后,再次提供更多示例,@DaveHughes,这些示例与您具体说明的格式不同。
  • @DaveHughes - 这就是为什么有一个 EDIT 解释 1)如何找到问题值 2)返回 NULL 而不是错误的替代表达式
  • 当 OP 接受除了显而易见的选择之外的其他东西时总是令人沮丧已经 +1。
【解决方案2】:

没有理由删除日期/时间类型。只需做一些简单的字符串解析:

cast(left(right('0' + WorkedHours, 5), 2) as int)
  + cast(right(WorkedHours, 2) as int) / 60.00

这不会有任何 24 小时或类似的限制。它只是假设冒号前有一位或两位数,冒号后有两位数。

【讨论】:

  • 嗨,这是我开始的地方,因为我不需要新数据库中的日期时间,只是一个小数,但我仍然有一个错误,从值为 0 的字符转换为 int . 我认为这可能是 0 值导致我在上述所有方法上出错,所以如果有人有解决方案来忽略 0:00 工作时间,这可能会起作用,我没想到这是一个问题直到你所有的 cmets
  • @Dave 00:00 是一个有效时间,所以我怀疑这就是错误所在。这些时间是否使用不同的格式?
  • @DaveHughes - 这非常很重要。你有'0:00''00:00' 的值吗? (你试过我的调试查询了吗?)
  • @MatBaile。你是对的,我确实声明它是 hh:mm 并且大多数是,我不知道表中的 h:mm 值为零会导致问题,因为任何值高于 1 分钟的值都采用 hh 格式:嗯,我没有写数据库,所以没有理由认为表格中可能有几个随机的 0:00 小时,但是在你告诉我我写的陈述是错误的之后,我搜索了表格,找到了' bad' times 运行了 shawnt00 编辑的答案,现在它可以完全按照我的需要工作,所以谢谢大家帮助我解决这个问题。
  • @DaveHughes - 运行try_convert(),根据我的回答和 larnu 的 cmets,一小时前,会为大家节省很多时间。
【解决方案3】:

这应该适用于 SQL Server 和示例字符串“1101:56”(1101 小时和 56 分钟)|一般从 0h 到 >24h:

-- Take all hours before ":" and all Minutes (2 digits) after ":" and convert it to decimal.
select convert(decimal,left('1101:56',CHARINDEX(':','1101:56')-1)) + ( convert(decimal,right('1101:56',2))/60 );

-- with column-placeholder "time_str_from_table"
select convert(decimal,left(time_str_from_table,CHARINDEX(':',time_str_from_table)-1)) + ( convert(decimal,right(time_str_from_table,2))/60 );

如果源表有 NULL 值,则使用“ISNULL”和替换值“0.0”:

-- with column-placeholder "time_str_from_table"
select isnull( ( convert(decimal,left(time_str_from_table,CHARINDEX(':',time_str_from_table)-1)) + ( convert(decimal,right(time_str_from_table,2))/60) ), 0.0);

【讨论】:

  • 为什么float的所有数据类型..?传统上,时间段适合以 2 为底的数值。
  • 你是对的。 “十进制”会是更好的选择吗?
  • 我建议这样做,是的。
猜你喜欢
  • 2021-01-17
  • 2017-07-21
  • 2015-09-23
  • 1970-01-01
  • 2011-09-01
  • 1970-01-01
  • 2014-11-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多