【问题标题】:Confusing type conversion error (date-to-varchar throwing string-to-datetime error)令人困惑的类型转换错误(date-to-varchar throwing string-to-datetime 错误)
【发布时间】:2019-03-27 18:33:15
【问题描述】:

我有一个表可以跟踪另一个表的插入、更新和删除。这种模式已经使用了多年,但是当我们添加对 DATE 列的跟踪时突然引入了一个错误。

这不是字符串格式问题。我的输入数据采用 ISO-8601 标准格式。

我已经删除了代码的所有必要部分来演示这个问题。

CREATE TABLE dbo.ChangeTrackingTable
(
    oldValue VARCHAR(100) NULL,
    newValue VARCHAR(100) NULL
);
GO
CREATE PROCEDURE dbo.usp_TestProcedure
(
    @name VARCHAR(100),
    @dateOfBirth DATE
)
AS
BEGIN
    INSERT INTO dbo.ChangeTrackingTable
    (
        oldValue,
        newValue
    )
    SELECT
        List.oldFieldValue,
        List.newFieldValue
    FROM
        (VALUES
            (NULL, @name, IIF(@name IS NOT NULL, 1, 0)),
            (NULL, @dateOfBirth, IIF(@dateOfBirth IS NOT NULL, 1, 0))
        ) AS List (oldFieldValue, newFieldValue, hasChanges)
    WHERE
        List.hasChanges = 1
END;
GO

VALUES 列表用于动态确定正在触摸哪些列。

当我只使用日期执行存储过程时,一切正常。

DECLARE @date DATE = GETDATE();

EXEC dbo.usp_TestProcedure
    @name = NULL,
    @dateOfBirth = @date;

/*
oldValue    newValue
NULL    2019-03-27
*/

但是,如果我尝试使用为 @name 提供的任何值来执行它,无论是否提供了 @date 的值,我都会收到以下错误。

DECLARE @date DATE = GETDATE();

EXEC dbo.usp_TestProcedure
    @name = 'Name',
    @dateOfBirth = @date;

--Conversion failed when converting date and/or time from character string.

如果我直接向INSERT 语句提供硬编码值,它就可以正常工作。所以我可以知道它不会在插入时发生在表级别。

如果我向这一行添加显式转换

(NULL, CAST(@dateOfBirth AS VARCHAR(100)), IIF(@dateOfBirth IS NOT NULL, 1, 0))

它也可以。

DATETIMEOFFSETDATETIMEDATETIME2 类型也会出现问题,所以我使用 DATE 不是问题。

我的问题是,当我尝试读取要插入到 VARCHAR 列中的 DATE 值时,为什么会出现 string > datetime 转换错误,但只有在存在另一个时才会出现在 VALUES 列表中List的结果集中的非日期值?

【问题讨论】:

    标签: sql-server datetime type-conversion


    【解决方案1】:

    在将问题本身提炼成基本结构时,我发现了潜在的答案。

    使用模式时

    SELECT *
    FROM
        (VALUES
            (NULL, @name, IIF(@name IS NOT NULL, 1, 0)),
            (NULL, @dateOfBirth, IIF(@dateOfBirth IS NOT NULL, 1, 0))
        ) AS List (oldFieldValue, newFieldValue, hasChanges)
    

    SQL Server 需要在内存中创建一个表,并且这些列中的每一个都需要一个分配的数据类型。此数据类型不是任意分配的,而是根据有据可查的Data Type Precedence 顺序有条不紊地分配。

    所有日期类型在此列表中都显示得非常高,因此我对DATE 的使用优先于也出现在表中的任何CHARVARCHAR 类型。

    List 表中的列被分配了最高优先级类型:DATE

    VARCHAR'Name' 被隐式转换为列的数据类型DATE 时,将引发错误。当@date 参数插入到表的VARCHAR 列中时不会。

    【讨论】:

      猜你喜欢
      • 2012-09-12
      • 1970-01-01
      • 2015-12-19
      • 2018-02-25
      • 2018-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-16
      相关资源
      最近更新 更多