2

我有一个使用执行 SQL 任务通过 SQL SSIS 执行的存储过程。

该任务具有以下内容:

USE [OPPY_DWUSD]
GO
DECLARE @return_value int
EXEC    @return_value = [dbo].[generate_merge_scdbk]
    @Schema = N'dim',
    @Dimension = N'VARIETY',
    @ETLSchema = N'stg',
    @ETLTable = N'vw_VARIETY',
    @Execute = 1

SELECT  'Return Value' = @return_value
GO

现在,按照我的设置方式,我有多个具有相同代码但值不同的执行 SQL 任务,大约 20 个执行 SQL 任务。

有没有更清洁的方法来解决这个问题?

4

2 回答 2

6

这是执行此操作的一种方法。该示例使用带有 SQL Server 2012 后端的 SSIS 2008 R2。

创建一个表来存储您的参数值。假设表名是dbo.SProcValues。根据您的存储过程定义,表架构将如下所示。

CREATE TABLE dbo.SProcValues(
    Id int IDENTITY(1,1) NOT NULL,
    SProcName nvarchar(40) NOT NULL,
    SchemaName nvarchar(20) NOT NULL,
    Dimension nvarchar(40) NOT NULL,
    ETLSchema nvarchar(20) NOT NULL,
    ETLTable nvarchar(40) NOT NULL,
    IsExecute bit NOT NULL
) 
GO

让我们使用以下脚本插入一些示例数据。

INSERT INTO dbo.SProcValues 
    (SProcName, SchemaName, Dimension, ETLSchema, ETLTable, IsExecute) VALUES
    ('dbo.sp_generate_merge', 'dim1', 'dimension1', 'stg1', 'table1', 1),
    ('dbo.sp_generate_merge_scdbk', 'dim2', 'dimension2', 'stg2', 'table2', 1),
    ('dbo.sp_generate_merge_scdbk', 'dim3', 'dimension3', 'stg3', 'table3', 0),
    ('dbo.sp_generate_merge', 'dim4', 'dimension4', 'stg4', 'table4', 0);
GO

在 SSIS 包上,假设您已经建立了数据源和连接管理器。创建以下变量。变量SProcValues将保存我们存储在上述表格中的参数集。变量SQLInnerQuery将保存稍后将在内部执行 SQL 任务中使用的查询。其他变量与表中可用的每一列相关,因此我们可以遍历每一行并将其保存在变量中。

将以下查询粘贴到变量SQLGetParameters的值中

SELECT SProcName, SchemaName, Dimension, ETLSchema, ETLTable, IsExecute FROM dbo.SProcValues

变量

选择变量SQLInnerQuery并按 F4 查看属性。将属性EvaluateAsExpression设置为True,然后在Expression属性上单击省略号按钮。

SQLInnerQuery

我们需要设置一个表达式来计算 EXEC 存储过程语句,该语句稍后可以提供给内部执行 SQL 任务。设置以下表达式。

"EXEC " + @[User::SProcName] + " @Schema = ?, @Dimension = ?, @ETLSchema = ?, @ETLTable = ?, @IsExecute = ?"

如果您单击编辑器上的 Evaluate Expression 按钮,您可以看到表达式的计算结果。您还会注意到下面的屏幕截图中没有存储过程名称,这是因为包变量 SProcName 当前没有任何值。在运行期间,SProcName 将被分配表中的值,并且此表达式将自动解析自身。 表达

在 SSIS 包上,拖放一个执行 SQL 任务。此任务将运行以下查询以获取存储在表 dbo.SProcValues 中的参数值列表。在执行 SQL 任务上配置常规页面,如下所示。该示例使用 OLEDB 连接,连接管理器/数据源被命名为 Practice。

第一次执行 SQL 任务 - 常规

配置执行 SQL 任务的结果集页面,将查询的结果集存储到对象变量中。

首次执行 SQL 任务 - 结果集

现在第一个 Execute SQL Task 已配置为获取应传递给存储过程的参数值列表,您需要遍历记录。

拖放一个 Foreach 循环容器。将执行 SQL 任务的优先级容器连接到 Foreach 循环容器。配置 Foreach 循环容器的 Collection 页面,如下所示。我们正在使用 ADO 枚举器遍历结果集。

Foreach 循环 - 集合

在 Foreach 循环容器上配置变量映射页面,如下所示。当我们遍历每一行时,我们将列值存储在各个变量中,以便我们可以将其传递给下一个执行 SQL 任务以运行存储过程。

Foreach 循环 - 变量映射

在 Foreach 循环容器中拖放一个 Execute SQL 任务,这样每次我们遍历结果集中的一行时都会执行该任务。如下所示配置执行 SQL 任务。

笔记

您可能希望根据您的要求在第二个执行 SQL 任务上配置ResultSet属性。如果选择 ResultSet,则需要配置适当的对象变量来接受结果集。对于本示例,我将其保留为None 。

第二次执行 SQL 任务 - 常规

配置要作为参数传递给存储过程的值。

第二次执行 SQL 任务 - 参数映射

最后,控制流看起来像这样。

控制流

当程序包运行时,循环将针对上述 SELECT 查询返回的尽可能多的记录执行存储过程,前提是您已将表行中定义的所有存储过程在数据库中可用。我已经创建了存储过程dbo.sp_generate_merge_scdbkdbo.sp_generate_merge具有相同的参数定义。这就是包成功执行的原因。

执行

于 2012-10-30T17:05:52.477 回答
3

你有正确的概念,只需要在执行 SQL 任务上使用变量、foreach 循环和参数等概念。

控制流

您的控制流看起来像这样

控制流

变量

我在 SSIS 中定义了 6 个变量

  • 尺寸 | 字符串 | 种类
  • ETLSchema | 字符串 | stg
  • 电子表格 | 字符串 | vw_VARIETY
  • 执行 | 整数32 | 1
  • 记录集 | 对象 | 系统对象
  • 架构 | 字符串 | 暗淡

第一个执行 SQL 任务将是一个查询或类似的可枚举的东西。目前,有一个硬编码查询来生成提供的查询值。您的解决方案可能只是一个 SELECT 的 UNIONed 链。此步骤的目标是填充 RecordSet 变量。

我的执行 SQL 任务返回完整的结果集 执行 SQL

我就这样把它推到我的对象里

结果集选项卡

ForEach 循环容器(ADO 记录集)

ForEach 循环容器将消耗我们事先建立的可枚举的东西。它将遍历每一行,我们将从对象中弹出值并将它们分配给局部变量。

将枚举器更改为Foreach ADO Enumerator. 选择我们用结果填充的对象User::RecordSet,然后使用枚举模式Rows in first table

FELC

在“变量映射”选项卡中,我们将确定值的基于序数的位置(第 0 列映射到变量 X)。这里唯一的技巧是确保您的 SSIS 变量数据类型与源查询的结果集中的数据类型相匹配。请注意,这是一个基于零的序数系统。

FELC 变量映射

此时,如果您单击运行,您会看到它枚举了您发送到 RecordSet 变量中的所有行。我发现此时运行它有助于确保我的所有数据类型都对齐。

内部执行 SQL 任务

我已经接受了您的查询并用占位符替换了硬编码值。将使用 OLEDB 连接?,而 ADO.NET 将使用命名的@varname.

执行 SQL 常规

在“参数映射”选项卡中,只需将这些局部变量映射到占位符。

执行 SQL 参数映射

现在你有一个很好的模板来运行具有不同值的相同过程。

于 2012-10-30T16:25:33.000 回答