Sql SSIS中带参数的日期计算结果不正确

Sql SSIS中带参数的日期计算结果不正确,sql,sql-server,tsql,ssis,etl,Sql,Sql Server,Tsql,Ssis,Etl,我想从数据源加载过去n天的数据。为此,我有一个项目参数“天数”。我在OleDB数据源中通过SQL命令和子句使用参数 WHERE StartDate >= CAST(GETDATE() -? as date) 此参数映射到项目参数Int32。但是,如果我想加载最后10天,它只给我最后8天 版本信息: SQL Server数据工具15.1.61710.120 服务器为SQL Server 2017标准版 我设置了一个测试包,数据越少越好。有以下数据源: 参数: 参数映射: T-S

我想从数据源加载过去n天的数据。为此,我有一个项目参数“天数”。我在OleDB数据源中通过SQL命令和子句使用参数

WHERE StartDate >= CAST(GETDATE() -? as date) 
此参数映射到项目参数Int32。但是,如果我想加载最后10天,它只给我最后8天

版本信息:

  • SQL Server数据工具15.1.61710.120
  • 服务器为SQL Server 2017标准版
我设置了一个测试包,数据越少越好。有以下数据源:

参数:

参数映射:

T-SQL表达式(错误的结果):

日期计算的SSIS表达式(正确结果):

我认为T-SQL表达式和SSIS表达式给出了相同的结果(今天减去10天),但当我运行包并将结果存储在表中时,情况并非如此。请参阅date_diff列,其中给出了8天而不是10天:

如果我用实际值替换参数,我确实会得到正确的结果

数据查看器还会显示错误的日期。部署包时,我得到的结果与调试器的结果相同

这是一个bug,还是我遗漏了什么?

我认为主要的问题是OLEDB source如何检测参数数据类型,我没有找到提到这一点的官方文档,但您可以做一个小实验来了解这一点:

尝试在OLEDB源中的SQL命令中写入以下查询:

SELECT ? as Column1
然后尝试分析查询,您将得到以下错误:

“@P1”的参数类型不能唯一推断;两种可能性是“sql_变体”和“xml”

这意味着查询解析器试图找出这些参数的数据类型,它与您映射到它的变量数据类型无关

然后尝试编写以下查询:

SELECT CAST(? AS INT) AS Column1
SELECT *
FROM dbo.DatabaseLog
WHERE PostTime < CAST(GETDATE() - ? as date)
declare @dt datetime
set @dt = 0
Select @dt
然后尝试分析查询,您将得到:

已成功分析SQL语句


现在,让我们将这些实验应用于您的查询:

尝试
选择CAST(GETDATE()-?AS DATE)作为第1列,您将得到一个错误的值,然后尝试
选择CAST(GETDATE()-CAST(?AS INT)AS DATE)作为第1列,您将得到一个正确的值

更新1-官方文件中的信息 从以下方面:

参数映射到在运行时提供参数值的变量。这些变量通常是用户定义的变量,不过您也可以使用Integration Services提供的系统变量。如果使用用户定义的变量,请确保将数据类型设置为与映射参数引用的列的数据类型兼容的类型

这意味着参数数据类型与变量数据类型无关


更新2-使用SQL事件探查器的实验 作为实验,我创建了一个SSIS包,将数据从OLEDB源导出到记录集目标。数据源是以下查询的结果:

SELECT CAST(? AS INT) AS Column1
SELECT *
FROM dbo.DatabaseLog
WHERE PostTime < CAST(GETDATE() - ? as date)
declare @dt datetime
set @dt = 0
Select @dt
第一个命令
exec[sys].sp\u descripe\u undeclared\u parameters
用于描述参数类型,如果单独运行,它将返回以下信息:

它表明参数数据类型被认为是
datetime

其他命令显示了一些奇怪的语句:

  • 首先,将
    @P1
    的值设置为
    1
  • 使用以下值执行最终查询
    1900-01-09 00:00:00
讨论 在SQL Server数据库引擎中,基准日期时间值为
1900-01-01 00:00:00
,可通过执行以下查询来检索:

SELECT CAST(? AS INT) AS Column1
SELECT *
FROM dbo.DatabaseLog
WHERE PostTime < CAST(GETDATE() - ? as date)
declare @dt datetime
set @dt = 0
Select @dt
另一方面,在SSI中:

由年、月、日、时、分、秒和分数秒组成的日期结构。分数秒具有7位数的固定刻度

DT_日期数据类型使用8字节浮点数实现。天数以整数增量表示,从1899年12月30日开始,午夜为时间零点。小时值表示为数字小数部分的绝对值。但是,浮点值不能代表所有实数;因此,在DT_日期中可以显示的日期范围有限制

另一方面,DT_DBTIMESTAMP由一个结构表示,该结构内部具有年、月、日、小时、分钟、秒和毫秒的各个字段。此数据类型对它可以显示的日期范围有更大的限制

基于此,我认为SSIS日期数据类型(
1899-12-30
)和SQL Server日期时间(
1900-01-01
)之间的日期时间基值存在差异,这导致在执行隐式转换以评估参数值时,两天内会出现差异


工具书类

您可以尝试DateAdd('day',-?,getdate()),而不是关闭getdate-?@Pascal Sanchez,这样可以正常工作。。。但我想知道为什么在SSMS中运行时,SELECT DATEADD(day,-10,getdate())和SELECT getdate()-10是相同的。对于OleDb,参数名称应该是0,1,2@谢谢,我修正了,但它不会改变结果。似乎与参数0等的作用相同。而不是0、1、2。如果简化测试,看看这些变量中到底放了什么<代码>选择?作为v0?作为v1?as v2谢谢,这很有意义。。。我检查了数据库实际接收到的查询以及参数:
(@P1 int、@P2 int、@P3 date、@P4 datetime)
如果您放入一个额外的
cast(?as int)
它将解析一个int。因此最后一个(P4)被解析为一个datetime,它应该是一个int