【问题标题】:SQL- convert varchar yyyymmdd-ttttt to iso 8601 formatSQL- 将 varchar yyyymmdd-ttttt 转换为 iso 8601 格式
【发布时间】:2018-11-06 13:43:24
【问题描述】:

我正在寻找一种将varchar yyyymmdd-ttttt 转换为iso 8601 格式的方法。这是我要转换的值的示例:

20120503-56320 

我已经试过了:

CONVERT(NVARCHAR(30), ia.alcreateStamp, 126) 

不会改变格式。先感谢您。

贝丝

【问题讨论】:

  • 您使用哪种编程语言?不知道就不可能回答你的问题。
  • 抱歉。 SQL。使用 SQL Server 2012
  • 56320 等于什么?
  • 56320 几点钟了?显然不是5:63:20。它可能是自午夜以来的秒数(时间为15:38:40),但这是我的猜测。
  • 56320 看起来不像任何有效时间 - 小时是 53?还是分钟63?无论那种格式是什么,它都不是yyyymmdd-ttttt

标签: sql sql-server datetime varchar iso8601


【解决方案1】:

这里的第一个问题是您将日期时间存储为(n)varchar。将日期和时间原样存储为datetimedatetime(2)

当使用CONVERT 将数据类型更改为(n)varchar 时,提供样式代码会告诉数据引擎相应数据类型中字符串应采用的格式(在本例中为datedatetime(2) 数据类型)。您正在将 nvarchar 转换为 nvarchar,因此样式代码将被完全忽略。

猜测 20120503-56320 的值是日期 2012-05-03 15:34:40(一天有 86400 秒,并且我假设 -56320 是一天中的秒数),因此要将您的值转换为您将使用的 datetime2

SELECT DateString,
       DATEADD(SECOND,CONVERT(int,RIGHT(V.DateString,LEN(V.DateString) - CI.I)),CONVERT(datetime2(0),LEFT(V.DateString,CI.I -1))),
       CONVERT(varchar(19),DATEADD(SECOND,CONVERT(int,RIGHT(V.DateString,LEN(V.DateString) - CI.I)),CONVERT(datetime2(0),LEFT(V.DateString,CI.I -1))),126)
FROM (VALUES('20120503-56320')) V(DateString)
     CROSS APPLY (VALUES(CHARINDEX('-',V.DateString))) CI(I);

老实说,在这一点上,你应该停下来。将datetime2 值传递给您的表示层并在那里处理格式。

但是,如果您真的想改进,请修复您的数据类型。一种方法可能是添加一个新的持久列:

ALTER TABLE YourTable ADD DateValue AS DATEADD(SECOND,CONVERT(int,RIGHT(DateString,LEN(DateString) - CHARINDEX('-',DateString))),CONVERT(datetime2(0),LEFT(DateString,CHARINDEX('-',DateString) -1))) PERSISTED;

【讨论】:

  • 感谢您的回复。不幸的是,我只有对该数据库的读取权限,所以我必须在我的 select 语句中进行转换。
  • @brose 理想情况下,您应该与设计数据库的人交谈并让他们解决他们糟糕的设计选择。
  • @brose 如果你必须这样做,然后将上面的表达式包装在另一个 CONVERT 中,如上所示。
  • 完美!我使用了上面的代码,把它塞进一个临时表中,然后用我的原始代码把它拉出来,就成功了。不确定这是否是最有效的方法,但它确实有效。非常感谢!
【解决方案2】:

假设格式为 YYYYMMDD- 后跟自午夜以来的秒数。

你可以通过在日期值上加上秒来构造你想要的值:

select dateadd(second, convert(int, right(str, 5)), convert(datetime, left(str, 8)))
from (values ('20120503-56320')) v(str)

这假定秒是零填充的,因此“1”将是“-00001”。如果不是这种情况,请使用:

select dateadd(second, convert(int, stuff(str, 1, charindex('-', str) , '')), convert(datetime, left(str, 8)))

或者(正如 Jeroen 指出的那样):

select dateadd(second, convert(int, stuff(str, 1, 9, '')), convert(datetime, left(str, 8)))

您也可以将其作为生成列直接合并到表中:

alter table t add alcreateStamp_dt as 
    ( dateadd(second, convert(int, stuff(str, 1, charindex('-', str) , '')), convert(datetime, left(str, 8))) );

这样您就不需要在每次将值作为datetime 时复制逻辑。

【讨论】:

  • 既然我们已经假设日期部分的长度是固定的,DATEADD(SECOND, CONVERT(INT, STUFF(str, 1, 9, '')), LEFT(str, 8)) 就可以了。
猜你喜欢
  • 2018-05-26
  • 2015-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-16
  • 1970-01-01
  • 2013-07-07
相关资源
最近更新 更多