代码之家  ›  专栏  ›  技术社区  ›  PeterDeV

SSIS中参数为的日期计算未给出正确的结果

  •  3
  • PeterDeV  · 技术社区  · 6 年前

    我想从数据源加载最近n天的数据。为此,我有一个项目参数“天数”。我将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表达式(正确结果):

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

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

    result

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

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

    这是个虫子,还是我在这里丢了什么东西?

    1 回复  |  直到 6 年前
        1
  •  4
  •   Hadi    6 年前

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

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

    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 Source - Documentation :

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

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


    更新2-使用SQL事件探查器的实验

    作为实验,我创建了一个ssis包,它将数据从OLEDB源导出到记录集目标。数据源是以下查询的结果:

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

    以及参数 ? 映射到类型为的变量 Int32 并且有价值 10

    在执行包之前,我在SQL Server实例上启动了SQL事件探查器跟踪,在执行包之后,以下查询将记录到跟踪中:

    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数据库引擎中,基本日期时间值为 1900-01-01 00:00:00 可以通过执行以下查询来检索:

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

    另一方面,在SSIS中:

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

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

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

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


    工具书类