Расчет даты с параметром в SSIS не дает правильного результата - PullRequest
0 голосов
/ 21 января 2019

Я хочу загрузить данные за последние n дней из источника данных.Для этого у меня есть параметр проекта "number_of_days".Я использую параметр в источнике данных OleDB с командой SQL с предложением

WHERE StartDate >= CAST(GETDATE() -? as date) 

Этот параметр сопоставляется с параметром проекта, Int32.Но, если я хочу загрузить последние 10 дней, он дает мне только последние 8 дней.

Информация о версии:

  • Инструменты данных SQL Server 15.1.61710.120
  • Сервер является стандартной версией SQL Server 2017.

Я настроил тестовый пакет с минимальным количеством данных.Есть этот источник данных:

data source

Параметр:

parameter

Отображение параметров:

parameter mapping

Выражение T-SQL (неверный результат):

CAST(GETDATE() -? as date)

Выражение SSIS для date_calc (правильный результат):

(DT_DBTIMESTAMP) (DT_DBDATE) DATEADD("DD", - @[$Project::number_of_days]  , GETDATE())

Я думаю, что TВыражение -SQL и выражение SSIS дают одинаковый результат (сегодня минус 10 дней), но это не тот случай, когда я запускаю пакет и сохраняю результаты в таблице.См. Столбец date_diff, который дает 8 дней вместо 10:

result

Если я заменю параметр на фактическое значение, я получу правильный результат.

Средство просмотра данных также показывает неправильную дату.При развертывании пакета я получаю тот же результат, что и отладчик.

Это ошибка или я что-то здесь упускаю?

1 Ответ

0 голосов
/ 21 января 2019

Я думаю, что основная проблема в том, как источник OLEDB определяет тип данных параметра, я не нашел официальной документации, в которой это упоминалось, но вы можете провести небольшой эксперимент, чтобы увидеть это:

Попробуйте написать следующий запрос в команде SQL в источнике OLEDB:

SELECT ? as Column1

А затем попытайтесь разобрать запрос, вы получите следующую ошибку:

Тип параметра для '@ P1' не может быть однозначно выведен; две возможности: «sql_variant» и «xml».

Это означает, что анализатор запросов пытается выяснить, какой тип данных у этого параметра, он не связан с типом данных переменной, который вы ему сопоставили.

Затем попробуйте написать следующий запрос:

SELECT CAST(? AS INT) AS Column1

А затем попытавшись разобрать запрос, вы получите:

Оператор SQL был успешно проанализирован.


Теперь давайте применим этот эксперимент к вашему запросу:

Попробуйте SELECT CAST(GETDATE() - ? AS DATE) as Column1, и вы получите неправильное значение, затем попробуйте SELECT CAST(GETDATE() - CAST(? AS INT) AS DATE) AS Column1, и вы получите правильное значение.

Обновление 1 - информация из официальной документации

Из следующего Источник OLEDB - Документация :

Параметры сопоставляются с переменными, которые предоставляют значения параметров во время выполнения. Переменные обычно являются пользовательскими переменными, хотя вы также можете использовать системные переменные, которые предоставляет Integration Services. Если вы используете пользовательские переменные, убедитесь, что вы установили для типа данных тип, совместимый с типом данных столбца, на который ссылается сопоставленный параметр.

Это означает, что тип данных параметра не связан с типом данных переменной.


Обновление 2 - эксперименты с использованием SQL Profiler

В качестве эксперимента я создал пакет служб SSIS, который экспортирует данные из источника OLEDB в пункт назначения набора записей. Источник данных является результатом следующего запроса:

SELECT *
FROM dbo.DatabaseLog
WHERE PostTime < CAST(GETDATE() - ? as date)

И параметр ? сопоставляется с переменной типа Int32 и имеет значение 10

Перед выполнением пакета я запустил трассировку SQL Profiler в экземпляре SQL Server, после выполнения пакета в трассировку были записаны следующие запросы:

exec [sys].sp_describe_undeclared_parameters N'SELECT *
FROM dbo.DatabaseLog
WHERE PostTime < CAST(GETDATE() -@P1 as date)'

declare @p1 int
set @p1=1
exec sp_prepare @p1 output,N'@P1 datetime',N'SELECT *
FROM dbo.DatabaseLog
WHERE PostTime < CAST(GETDATE() -@P1 as date)',1
select @p1

exec sp_execute 1,'1900-01-09 00:00:00'

exec sp_unprepare 1

Первая команда exec [sys].sp_describe_undeclared_parameters должна описать тип параметра, если мы запустим его отдельно, он вернет следующую информацию:

enter image description here

Показывает, что тип данных параметра рассматривается как datetime.

Другие команды показывают странное утверждение:

  • Сначала значение @P1 устанавливается на 1
  • Окончательный запрос выполняется со следующим значением 1900-01-09 00:00:00

Обсуждение

В ядре базы данных SQL Server базовое значение datetime равно 1900-01-01 00:00:00, которое можно получить, выполнив следующий запрос:

declare @dt datetime
set @dt = 0
Select @dt

С другой стороны, в SSIS:

Структура даты, состоящая из года, месяца, дня, часа, минуты, секунд и дробных секунд. Дробные секунды имеют фиксированную шкалу из 7 цифр.

Тип данных DT_DATE реализован с использованием 8-байтового числа с плавающей запятой. Дни представлены приращениями целых чисел, начиная с 30 декабря 1899 , а полночь - нулевое время. Часовые значения выражаются как абсолютное значение дробной части числа. Однако значение с плавающей запятой не может представлять все реальные значения; следовательно, существуют ограничения на диапазон дат, которые могут быть представлены в DT_DATE.

С другой стороны, DT_DBTIMESTAMP представлен структурой, которая внутренне имеет отдельные поля для года, месяца, дня, часов, минут, секунд и миллисекунд. Этот тип данных имеет большие ограничения на диапазоны дат, которые он может представлять.

Исходя из этого, я думаю, что существует разница между базовым значением datetime между типом данных даты SSIS (1899-12-30) и datetime SQL Server (1900-01-01), что приводит к разнице в два дня при выполнении неявное преобразование для оценки значения параметра.


Ссылки

...