Непонятная ошибка преобразования типов (ошибка преобразования даты в дату в строке) - PullRequest
0 голосов
/ 27 марта 2019

У меня есть таблица, которая отслеживает вставки, обновления и удаления в другую таблицу. Этот шаблон использовался годами, но внезапно привел к ошибке, когда мы добавили отслеживание столбца 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 используется для динамического определения, какие столбцы касаются.

Когда я выполняю sproc только с датой, все работает нормально.

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 для вставки в столбец VARCHAR, но только в список VALUES, если существует другой ненулевое значение в наборе результатов для List?

1 Ответ

0 голосов
/ 27 марта 2019

Уточняя сам вопрос до его базовой структуры, я нашел основной ответ.

При использовании шаблона

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 необходимо будет создать таблицу в памяти, и каждому из этих столбцов необходим назначенный тип данных. Этот тип данных присваивается не произвольно, а методично в соответствии с хорошо документированным порядком Тип данных Приоритет .

Все типы дат отображаются в этом списке очень высоко, поэтому мое использование DATE имеет приоритет над любым типом CHAR или VARCHAR, также присутствующим в таблице.

Столбцу в моей таблице List присвоен тип с наивысшим приоритетом: DATE.

Ошибка генерируется, когда значение VARCHAR, 'Name' неявно приводится к типу данных столбца, который равен DATE. Не тогда, когда параметр @date вставляется в столбец VARCHAR таблицы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...