SSIS - 如何在OLE DB Source中为参数化复杂多语句脚本创建参数,并通过此参数与另一个源连接

时间:2016-12-28 19:45:43

标签: sql sql-server sql-server-2008 ssis ssis-2008

我遇到了以下SSIS问题。我需要为数据流组件(SQL Server 2008)中的OLE DB源创建一个复杂的参数化脚本。除此之外,我需要通过script参数将其与另一个OLE DB源连接。本练习的目的是根据脚本中指定的条件在输出列中设置值。该脚本应如下所示(这是简化版本,涉及多个IF语句和复杂连接的复杂程度要高得多):

declare @ind int
set @ind=0
if (select status from contracts where contract_id=?)=1
  then @ind=1
if (select year(completion_date) from orders where contract_id=?)>2012
  then @ind=1
select @ind

问题:

  1. 如果脚本包含除简单SELECT(IF,声明等)之外的任何内容,则不允许我映射参数,得到“无法从SQL命令中提取参数”错误。这是它的工作方式吗?然后,我想,我可能需要将其移至存储过程......
  2. 即使使用存储过程,我仍然面临着主要的障碍 - 我需要通过contract_id字段将此OLE DB源组件映射到另一个源,这是此查询中的参数。我怎么能完成它?

1 个答案:

答案 0 :(得分:1)

利奥,

首先是一点背景。在ole db源组件中使用带有参数的sql查询时,需要做两件事。一个是,需要确定(未声明的)参数的数据类型,第二个是需要确定的查询输出的元数据。

我说这些参数是未声明的,因为在sql命令中转到SQL Server ,没有声明语句定义这些参数的数据类型。因此,从SQL Server的角度来看,它不知道数据类型,因此这些参数是未声明的。将其与我们在SSMS中编写相同查询的方式进行比较;我们首先声明变量(例如:声明@my_var int;从表中选择val,其中col = @my_var;这里,我们预先声明了我们的@my_var变量。)。

因为参数是"未声明",在针对SQL Server运行查询时,首先需要确定这些参数的数据类型。在这方面,SQL Server 2012以上的功能比以前的版本更好。

在SQL Server 2012中,引入了一个名为sys.sp_describe_undeclared_parameters的新proc。此过程有助于推断参数的数据类型,即使对于复杂的tsql语句也是如此。它可能并不总是提供您期望的数据类型,但您可以提供足够的提示以获取所需的确切数据类型。但是,这仅适用于SQL Server 2012及更高版本。

您说您正在使用SQL Server 2008.在2008年,驱动程序(Native Client 10.x)创建一个特殊的select语句(包含分配参数的列)并使用fmtonly推断未声明的数据类型参数。在我的测试中,这仅适用于更简单的情况,并且在更复杂的tsql语句中失败。因此,您收到错误消息,指出"提供商不具备..."。但是,如果您将逻辑封装在存储过程中并具有这些存储过程的参数,则SQL Server可以轻松地找到这些存储过程的数据类型" undeclared"参数。因为:当我们创建存储过程时,我们声明参数的数据类型,2008驱动程序使用sys.sp_procedure_params_100_rowset proc来获取数据类型。

因此,使用带有预定义参数的存储过程可能是您前往此处的方式(因为您在2008年)。但是,如果您迁移到2012或更高版本,则可以依赖更新的功能。

至于获取查询输出元数据的后半部分,具有临时表将构成挑战。如果您使用的是SQL Server 2008,则可以使用fmtonly的一些创造性使用来解决存储过程中临时表的存在问题(在线搜索或转到here)。如果您使用的是SQL Server 2012及更高版本,则可以使用WITH RESULT SETS子句来处理临时表。

更新(基于Leo的下面第一条评论):

简短的回答是肯定的。在2008年的世界中,无法解析复杂的tsl语句来推断参数及其数据类型。看起来只有简单的选择语句或" exec proc"陈述是正确的候选人。使用SELECT语句,JOIN是可以的; UNION / INTERSECT / EXCEPT等运算符都可以(只要每个单独的语句都是一个select语句)。子查询不行。甚至在简单的select / exec之前的注释标签也会引发错误。

这就是我观察到2008年驾驶员在幕后发生的事情。让我们说以下是我们的选择语句与params:

select A.col_a, A.col_b from dbo.MyTable A where A.col_c = ? and A.col_d = ?

然后,在推断参数类型时,驱动程序或BIDS(不确定是哪个)构造并将以下sql命令发送到数据库:

set fmtonly on;
select col_c, col_d from dbo.MyTable where 1 = 2;
set fmtonly off;

注意,构造这个sql语句。它包含将params分配到的两列(col_c和col_d)。此外,还有一个where子句来阻止任何实际的行返回。构造完成后,这个语句基本上被发送到sql server,这样就可以知道这两列的数据类型是什么了;然后将这些数据类型分配给我们未声明的参数。

因此,试图推断这些数据类型的进程(驱动程序或BIDS)只能在更简单的场景中构造这些sql语句,并且在复杂的场景中无法这样做;此时它会抛出错误

但是,如果您在2008年使用procs,则不会构建特殊的sql语句,而是使用sys.sp_procedure_params_100_rowset proc来推断数据类型。

最后,如果您要使用2012(或以后),新添加的proc sys.sp_describe_undeclared_pa​​rameters功能更强大,并且可以处理一些复杂的场景。基本上,在这里,来自oledb src组件的sql语句(无论它是什么)作为上述proc的输入发送;并且proc返回描述参数数据类型的数据集。因此,对于我们的例子,在2012年,这将会发生:

exec sys.sp_describe_undeclared_parameters N'select A.col_a, A.col_b from dbo.MyTable A where A.col_c = ? and A.col_d = ?'