令人困惑的类型转换错误(日期至varchar引发字符串至日期时间错误)

时间:2019-03-27 18:33:16

标签: sql-server datetime type-conversion

我有一个表,该表跟踪对另一个表的插入,更新和删除。这种模式已经使用了多年,但是在我们添加对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的使用不是问题。

我的问题是,当我尝试读取要插入string > datetime列中的DATE值,但仅在{{ 1}}列出VARCHAR的结果集中是否存在另一个非日期值?

1 个答案:

答案 0 :(得分:0)

在将问题本身简化为基本结构时,我发现了潜在的答案。

使用图案时

VALUES

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

所有日期类型在此列表中都显得很高,因此我对List的使用要优先于表中也出现的任何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) DATE类型。

我的CHAR表中的列分配了最高优先级类型:VARCHAR

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