我有一个表,该表跟踪对另一个表的插入,更新和删除。这种模式已经使用了多年,但是在我们添加对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))
它也可以正常工作。
DATETIMEOFFSET
,DATETIME
和DATETIME2
类型也出现问题,所以我对DATE
的使用不是问题。
我的问题是,当我尝试读取要插入string > datetime
列中的DATE
值,但仅在{{ 1}}列出VARCHAR
的结果集中是否存在另一个非日期值?
答案 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
。
将List
值DATE
隐式转换为列的数据类型VARCHAR
时,将引发错误。将'Name'
参数插入到表的DATE
列中时不会。