【问题标题】:Why does this char value not convert to datetime?为什么这个 char 值不转换为日期时间?
【发布时间】:2019-07-02 22:44:05
【问题描述】:

我有一个性能监视器实例,将数据保存到 MS SQL 服务器数据库上的表中。性能数据保存到名为 CounterData 的表中。该表有一个 char(24) 字段 (counterdatetime) 用于存储数据的日期/时间。我试图将该字段视为日期时间数据,但我不断收到“从字符串转换日期和/或时间时转换失败。”

以下是来自 counterdatetime 的数据示例:2019-07-02 09:19:46.300

我尝试了 CAST 和 CONVERT 的不同变体,以允许我将这些数据作为日期时间处理。例如:

SELECT CAST(counterdatetime as datetime) from CounterData
SELECT CAST(counterdatetime as datetime2) from CounterData
SELECT CONVERT(datetime,counterdatetime,101) from CounterData

每个都给我“转换失败......”错误。我想也许失败是由一条记录中的虚假值触发的,所以我尝试使用指定一个好值的 WHERE 表达式来限制转换。我还尝试了转换值本身,如下所示:

SELECT CAST('2019-07-02 09:19:46.300' as datetime)

在这种情况下,CAST 有效。

为什么当我从表格中选择值时它不起作用?

更新

@Jeroen Mostert 在评论中提供了答案,我将其作为答案发布。

【问题讨论】:

  • "The table has a char(24) field... I'm trying to treat that field as a datetime data" 不要那样做!如果您有 DateTime 值,请使用 DateTime 系列中的类型存储它们!
  • 我不相信'2019-07-02 09:19:46.300' 是导致您的查询崩溃的实际值。你确定吗?
  • @JoelCoehoorn 使用 char(24) 不是我的选择。这就是性能监视器创建表的方式。
  • 呃-哦,意大利面条-O。那是一个不属于那里的NUL 字符。这些非常糟糕,因为REPLACE 默认情况下不知道如何处理它们。试试CONVERT(DATETIME, REPLACE(CounterDateTime COLLATE Latin1_General_BIN2, CHAR(0), ''))。 (SUBSTRING(CounterDateTime, 1, 23) 在这种情况下也应该可以工作,因为我们可以预期 NUL 总是在最后。)
  • 一次性转换所有内容(因为一遍又一遍会很烦人):UPDATE CounterData SET CounterDateTime = SUBSTRING(CounterDateTime, 1, 23); ALTER TABLE CounterData ALTER COLUMN CounterDateTime DATETIME 应该负责打字。或 INSERT 另一个表中的内容,其中包含正确键入的列。如果您需要更灵活的永久设置,应该可以让 perfmon 使用 INSTEAD OF 触发器将其数据插入到视图中,该触发器将在数据有机会变得烦人之前转换数据。

标签: sql-server tsql


【解决方案1】:

我不确定文字 '2019-07-02 09:19:46.300' 是否是实际上使您的查询崩溃的文本值。如果您使用的是 SQL Server 2012 或更高版本,则有一个帮助函数 TRY_CONVERT 将尝试将输入字符串转换为特定类型(在本例中为日期时间),并将返回转换后的日期时间值或 NULL如果转换失败。

尝试运行以下查询:

SELECT
    counterdatetime
FROM CounterData
WHERE
    TRY_CONVERT(datetime, counterdatetime) IS NULL;

如果您看到结果集中出现任何记录,则表示这些值无法成功转换。

【讨论】:

  • 查询返回表中的所有行。我不明白的是为什么这些值无法转换。
  • 您需要给我们一组可重复的样本数据,否则我们所能做的就是做出有根据的猜测(就像我在这里所做的那样)。请在您的问题中添加一些示例数据。
  • 不,请编辑您的问题,以便其他人也可以轻松读取数据。
  • 查看我对问题的更新。 SELECT 返回的文字值不是问题。它们很好,但似乎 char(24) 字段除了 SELECT 返回的文字字符串之外还包含其他内容。
  • @DWLangham 看起来您在 cmets 中得到了准确的答案/修复。
【解决方案2】:

yyyy-MM-dd hh:mm:ss.sss 在使用datetime 数据类型时不是明确的格式;它会因语言而异。

举以下例子:

SET LANGUAGE ENGLISH; --American
SELECT CONVERT(datetime,'2019-07-06'); --Returns 06 July 2019

SET LANGUAGE BRITISH; --English
SELECT CONVERT(datetime,'2019-07-06'); --Returns 07 June 2019

如果我们然后像下面这样约会,看看会发生什么:

SET LANGUAGE ENGLISH; --American
SELECT CONVERT(datetime,'2019-01-31'); --Returns 01 January 2019

SET LANGUAGE British; --English
SELECT CONVERT(datetime,'2019-01-31'); --Conversion error

但是,实际上,您不应该将日期存储为char,您需要解决这个问题。幸运的是,您可以通过将数据更改为 ISO 格式 yyyy-MM-ddThh:mm:ss.sss 来轻松修复数据:

UPDATE CounterData
SET counterdatetime = STUFF(counterdatetime,11,1,'T');

ALTER TABLE CounterData ALTER COLUMN counterdatetime datetime;

【讨论】:

  • 大家,请停止宣传我不应该将日期值存储为字符。我知道。在这种情况下,选择不是我的。
  • 这不会改变我的问题@DWLangham 的主要部分。 yyyy-MM-dd hh:mm:ss.sss is 不是明确的,STUFF 表达式会成功并允许您成功转换行(前提是它们是 all 的格式)。或者,如果您的值实际上精确到 1/1000 秒,而不是 1/300,则使用 datetime2(3)
  • 我在只有 10 行的表格副本上尝试了您的建议。 UPDATE 命令将 CounterDateTime 值更改为如下所示:2019-07-01T16:35:41.364。但是 ALTER TABLE 命令失败并显示“从字符串转换日期和/或时间时转换失败”。我还尝试将 datetime2 指定为 ALTER TABLE 的类型并得到相同的错误。
  • 听起来您的行的值不是yyyy-MM-dd hhh:mm:ss.sss 格式,然后是@DWLangham。 TRY_CONVERT是你这里的朋友,但你现在无法改变系统恐怕是在打一场失败的战斗;你最好和你的系统设计师谈谈,让他们在问题变得更糟之前解决问题。
【解决方案3】:

该表有一个 char(24) 字段...我正在尝试将该字段视为日期时间数据

不要那样做!如果您有 DateTime 值,请使用 DateTime 系列中的类型存储它们!希望这整件事是修复(因为现在,架构真的是损坏)这个表的项目的一部分。这只是为什么这很重要的一个(众多)示例,该列上的索引几乎没有用处。

我认为失败可能是由一条记录中的虚假值触发的......

正是正在发生的事情。有不良数据。 (使用真正的 DateTime 类型将首先防止这种情况发生)。

...所以我尝试使用指定良好值的 WHERE 表达式来限制转换。

再次检查您的WHERE 子句,因为它不够具体,或者您选择的值有问题,您一开始没有看到。

【讨论】:

    【解决方案4】:

    @Jeroen Mostert 在对原始帖子的评论中提供了正确答案,因此应该归功于他。

    呃-哦,意大利面条-O。那是一个不属于的 NUL 字符 那里。这些非常糟糕,因为 REPLACE 不知道该怎么做 默认情况下使用它们。尝试 CONVERT(DATETIME, REPLACE(CounterDateTime 整理 Latin1_General_BIN2,CHAR(0),''))。 (SUBSTRING(CounterDateTime, 1, 23) 在这种情况下也应该工作, 因为我们可以期望 NUL 总是在最后。)

    【讨论】:

      猜你喜欢
      • 2013-09-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-23
      • 1970-01-01
      • 1970-01-01
      • 2016-12-31
      • 2021-07-23
      相关资源
      最近更新 更多