MSSQL - 从货币转换为日期时间数据类型

时间:2018-04-06 12:40:47

标签: sql sql-server

感谢一些精彩的应用程序设计,我发现自己与一个真正的WTF面对面 - 似乎我支持的应用程序将日期和时间输出到一个特定表中的两个单独的列中;日期作为datetime数据类型进入“日期”列,而时间作为money数据类型以分钟和秒为单位进入“时间”列(例如,10: 35:00将是10.35英镑。

我需要在我对数据库进行查询期间合并这两列,以便它返回一个完整的datetime列,但显然只是...

...snip...
CAST(au.[Date] as datetime) + CAST(au.[Time] AS datetime) as 'LastUpdateDate'
...snip...

......不会像我希望的那样(天真地)它会起作用。

我的前任遇到了这个问题,并想出了一个......“创造性”的解决方案:

MIN(DATEADD(HOUR,CAST(LEFT(CONVERT(VARCHAR(10),[time],0),CHARINDEX('.',CONVERT(VARCHAR(10),[time],0),0)-1) AS INT),DATEADD(MINUTE,CAST(RIGHT(CONVERT(VARCHAR(10),[time],0),LEN(CONVERT(VARCHAR(10),[time],0)) - CHARINDEX('.',CONVERT(VARCHAR(10),[time],0),0)) AS INT),[date]))) AS CreatedDateTime

与我的前任不同,我宁愿尽量保持这个解决方案。您是否认为可以通过以下方式将此列中的值转换为:

  1. 将money值转换为字符串
  2. 替换冒号的小数点
  3. 将此解析为datetime对象(替换第一个代码块的CAST(au.[Time] as datetime)部分
  4. 这可行吗?如果没有,任何人都可以提供帮助吗?

    修改

    为了100%明确,我无法更改列的基础数据类型,因为应用程序依赖于money的数据类型。这纯粹是我理智的应用程序,管家报告实际上可以将数据作为完整的datetime值读取。

3 个答案:

答案 0 :(得分:1)

我更喜欢没有任何弦乐演员的算术转换

MIN(
    DATEADD(
        MINUTE, 
        FLOOR(au.[Time]) * 60 + (au.[Time]-FLOOR(au.[Time])) * 100, 
        au.[Date])
) AS CreatedDateTime

答案 1 :(得分:1)

如果将列更改为time,则可以添加一层完整性:

ALTER TABLE ... ADD SaneDate AS 
    DATEADD(MINUTE, FLOOR([Time]) * 60 + 100 * ([Time] - FLOOR([Time])), [Date])

一个计算列,然后您可以坚持使用它而不是在任何地方重复计算。如果以任何方式更改表是不可能的,您至少可以创建一个视图或表值函数来捕获此逻辑。 (最好不是标量函数,虽然它更明显 - 那些在查询中有可怕的表现。)

我倾向于在可能的情况下更喜欢DATEADD字符串操作,因为结果往往更容易预测。在这种情况下,没有真正的问题,因为无论语言设置如何,将money转换为char(5)都是完全可预测的,但仍然可以。

答案 2 :(得分:0)

刚看了一下如何使用REPLACE命令,它按预期工作:

CAST(au.[Date] as datetime) + CAST(REPLACE(CAST(au.[Time] AS varchar(5)),'.',':') AS datetime) as 'LastUpdateDate'

现在输出2018-01-10 10:32:00.000,而在它提供一些不正确的日期和时间值之前。

我想你可以像@JeroenMostert建议的那样在数学上对它进行转换 - 公平地说,我不是100%对这个解决方案可能对计算分钟并将其转换成这样的性能影响因此我会试一试同样可以确定。