这是我参与11月更文挑战的第15天,活动详情查看:2021最后一次更文挑战
翻译参考
本文主要参考翻译自 The Stairway to Integration Services
系列文章的 Advanced SSIS Workflow Management – Level 8 of the Stairway to Integration Services,目的在于对 SSIS 有一个全面清晰的认识,所有内容在原文的基础上进行实操,由于版本差异、个人疑问等多种原因,未采用完全翻译的原则,同时也会对文中内容进行适当修改,希望最终可以更有利于学习和了解 SSIS,
感谢支持!
高级SSIS工作流管理
在之前的部分,我们创建了一个 新SSIS包,首先查看了脚本任务和SSIS中的优先约束。检查了 MaxConcurrentExecutables
包属性。还检查、演示和测试了优先约束的 “On Success”, “On Completion” 和 “On Failure” 功能。
本篇中,将深入了解 SSIS工作流管理 —— 学习 SSIS 变量和复杂的优先约束表达式。
关于变量(About Variables)
打开 Precedence.dtsx
包(如果没打开的话)。点击 visual studio
顶部的 SSIS 下拉菜单,点击选中 "变量"(Variables
) 菜单项,打开显示变量窗口。
在 变量窗口(Variables window) 的顶部,可以发现SSIS变量的工具条,这些按钮是:
- 添加变量
- 移动变量
- 删除变量
- 网格选项
在网格选项中,可以设置是否显示系统变量,以及变量窗口表格中显示的列。
系统变量是
System
命名空间下的变量。许多SSIS包属性、或SSIS包中创建的组件、对象属性都是系统变量。
变量和命名空间(Variables and Namespaces)
SSIS包中有两个默认命名空间:System
和 User
。我们不能添加系统变量,但是可以添加 用户变量 或者 创建一个新命名空间。作用域和命名空间下的 变量名 必须是唯一的。
比如,在 "User" 命名空间中你可以有一个 "MyVariable" 变量名,完全限定名称是 "User::MyVariable"(<Namespace>::<VariableName>
)。当前例子中,User::MyVariable
位于 Precedence.dtsx
包作用域中。我们可以在 "User2" 命名空间中有另一个变量 "MyVariable",User2::MyVariable
也是位于 Precedence.dtsx
包作用域。
为了创建 User2
命名空间,你需要显示命名空间列,并编辑"User"文本为"User2"。当在相同的作用域访问位于不同命名空间的相同名称变量时,你需要使用完全限定变量名,否则你将收到一个如下类似的错误:
变量名称不明确,因为具有该名称的多个变量存在于不同的命名空间中。指定名称空间限定名称以防止歧义。
The variable name is ambiguous because multiple variables with this name exist in different namespaces. Specify namespace-qualified name to prevent ambiguity.
添加变量(Add a Variable)
点击 变量窗口 的 "添加变量" 按钮,一个新的 Int32 数据类型的名为"变量"(Variable
)的变量被创建。
重命名变量为"MyBool",修改它的数据类型为 Boolean。
现在,可以在优先约束表达式中使用该变量了。
表达式和优先约束
右击 “Script Task 1” 和 “Script Task 2” 之间的优先约束,点击 "编辑...",打开优先约束编辑器
这里有两组控制按钮,分别是 "约束选项"(Constraint options
) 和 "多重约束"(Multiple constraints
)。在构建SSIS包时,我将控制流任务定向为从上到下的顺序执行(top-to-bottom
)。
位置任务(positioning tasks
)的一个积极的副作用是执行流从上到下。优先约束编辑器上的 组框(groupboxes
) 的排列与控制流上优先约束的物理布局在某种程度上保持一致:"约束选项"(Constraint options
)组框 设置优先约束中与上一个任务或优先约束"起点"相关的属性;"多重约束"(Multiple constraints
)组框 设置有关下一个任务或优先约束"端点"的属性。
在优先约束编辑器中,点击 "求值运算"(Evaluation operation
) 下拉列表。可以看到几个选项列表:
- 约束
Constraint
- 表达式
Expression
- 表达式和约束
Expression and Constraint
- 表达式或约束
Expression or Constraint
默认选项是约束(之前的介绍都是使用的这个选项)。约束允许配置何时或是否执行下一个任务 —— 仅仅根据上一个任务的执行结果。值下拉列表包含约束评估的选项:成功,失败和完成。
优先约束中使用表达式
修改 "求值运算"(Evaluation operation
) 下拉列表为 "表达式"(Expression
),并在表达式文本框中输入"@MyBool"
点击 "测试"(test
) 按钮,验证表达式文本框中的表达式。
SSIS 变量 MyBool 是一个 Boolean 类型的值,其默认值为False。表达式文本框中的值必须是 True 或 False。此处也可以编辑表达式为"@MyBool == True"。表达式"@MyBool"和"@MyBool == True"在逻辑上是相等的,因为它们有相同的结果。
配置好后,关闭优先约束编辑器。
调试运行 'Precedence.dtsx' 包。运行 "Script Task 1" 出现询问成功或失败的消息框。此时,无论你选择哪个选项都没关系,因为优先约束评估仅仅基于 SSIS 的 Boolean 变量@MyBool
的值。@MyBool
默认是 False,所以 "Script Task 2" 将永远不会执行(因为优先约束永远不能评估为True)
脚本任务的脚本中使用变量
下面创建更有用的测试。
打开 "Script Task 1" 编辑器,并点击 "ReadWriteVariables" 属性的省略号,显示选择变量窗口,选择 User::MyBool
变量。
点击确定按钮,关闭选择变量窗口,脚本任务编辑器的 ReadWriteVariables
属性现在包含了 SSIS 变量 "User::MyBool"。
点击"编辑脚本"(Edit Script
)按钮,在 Main 函数中编辑代码如下:
public void Main()
{
// TODO: Add your code here
var sTaskName = Dts.Variables["TaskName"].Value.ToString();
var boxRes = MessageBox.Show("设置MyBool为True?", sTaskName, MessageBoxButtons.YesNo);
if (boxRes == DialogResult.Yes)
{
Dts.Variables["User::MyBool"].Value = true;
}
else
{
Dts.Variables["User::MyBool"].Value = false;
}
Dts.TaskResult = (int)ScriptResults.Success;
}
保存并关闭脚本编辑器,点击"确定"关闭脚本任务编辑器。
调试运行 Precedence.dtsx
包,分别测试点击 "Script Task 1" 中消息框的不同按钮:点"是"时会执行"Script Task 2";点"否"时,整个执行将在不执行"Script Task 2"情况下结束。
深入使用变量
右击 "Script Task 2",点击复制,然后右击控制流的空白部分,点击"粘贴"。将会出现 "Script Task 2 1" 脚本任务。
重命名 "Script Task 2 1" 为 "Script Task 3",从 "Script Task 1" 连接一个新的"优先约束"。
如果此时执行SSIS包,不管你点击设置的 MyBool 变量,"Script Task 1"都会执行成功,连接 "Script Task 1" 和 "Script Task 3" 的优先约束将会评估为True,消息框 "Script Task 3 completed" 将会显示。
右击 "Script Task 1" 和 "Script Task 3" 之间的有限约束,打开优先约束编辑器,改变 "求值操作"(Evaluation Operation) 为 “表达式”。在表达式文本框中输入 "!@MyBool",如下:
"!@MyBool" 表示 "Not MyBool"。点击确定按钮关闭编辑器。目前控制流应该和下面的相似
执行SSIS包,如果你点击 "Script Task 1" 提示框的"是"按钮,"Script Task 2" 将会执行;如果你点击"否"按钮,"Script Task 3" 将会执行
原文中有关于优先约束颜色的视觉反馈的介绍。实际上,在 Visual Studio 2010 shell(SQL Server 2012) 中,视觉反馈并没有起到足够的作用,因为其颜色并没有在相应状态下改变。可能和版本不同,此处省略此段内容。
复制并禁用以保留现有工作
在进行更多操作之前,让我们保留已经完成的工作。
从SSIS工具箱(toolbox)中,拖拽 “序列容器”(Sequence Container
) 到控制流中。
SSIS工具箱的显示,可以通过顶部菜单 SSIS 中的菜单项 "SSIS工具箱" 控制
点击 控制流 的空白处,并围绕着三个脚本任务(script task)画一个盒子,可以将它们作为一组,整体拖拽到序列容器中
拖进入后,大多数时候,序列容器会自动调整大小围绕这些项。如果没有,可以手动调整大小。
右键 序列容器,点击 "复制"。然后,右击控制流的空白处,点击"粘贴"。此时控制流应该如下所示:
右击第一个序列容器(原始的那个),点击 "禁用"(Disable),序列容器和它的内容显示为禁用(变灰)
现在,当进行新工作时,我们可以保留已经完成的工作。
多重约束(Multiple Constraints
)
在 "序列容器1" 中,删除 "Script Task 1"。同时也会删除 "Script Task 1" 与 "Script Task 2"/"Script Task 3" 之间的优先约束。复制 "Script Task 2" 并粘贴到 "序列容器1",重命名新脚本任务为"Script Task 4"。
移动和调整 "Script Task 2" 和 "Script Task 4"并排显示,"Script Task 2" 和 "Script Task 3"、"Script Task 4" 和 "Script Task 3"之间各自连接一个优先约束
现在,先考虑一下:为了使 "Script Task 3" 执行,必须做什么?
- 什么都不做。其他任务执行时,"Script Task 3" 也执行。
- "Script Task 3" 在 "Script Task 4" 或 "Script Task 2" 执行并成功之后执行。
- "Script Task 3" 在 "Script Task 4" 和 "Script Task 2" 执行并成功之后执行。
- "Script Task 3" 永远不执行。
可以通过检查两个 优先级约束编辑器 来找到答案,焦点放在 “多重约束” 组框上:
记住,多重约束框组 定义优先约束如何在端点(
EndPoint
,优先约束结束的箭头)工作。当端点上只有一个优先约束落在任务上是,这些选项没有意义(它们的行为方式相同)。但是,当有多个约束落在端点任务上时(如此处所示),这些选项至关重要。
"逻辑与"(Logical AND
) 选项是默认选中的。意味着端点任务执行前,位于该端点任务上的所有优先约束必须评估。在此例中,它意味着 "Script Task 4" 和 "Script Task 2" 必须结束和成功,"Script Task 3" 才会触发。执行SSIS包进行验证。
直到 "Script Task 4" 和 "Script Task 2" 完成执行并成功,"Script Task 3" 才会开始执行(上面第3个答案)。这是逻辑与多重约束的作用。
下面测试 "逻辑或"(Logical Or
)。停止调试运行,双击启用的优先约束中的一个打开编辑器,将多重约束更改为"逻辑或"。点击“确定”,关闭优先约束编辑器。连接"Script Task 3"的两个优先约束都变成了虚线表示。
由于多重约束处理的是端点任务(endpoint tasks)。对一个的改变将应用到所有连接到端点任务的优先约束。
之前,多重约束配置为"逻辑与",前面的优先约束必须都在执行后续任务之前进行评估。
现在配置为"逻辑或","Script Task 3" 执行前会做什么?此处是上面的答案2:"Script Task 3" 在 "Script Task 4" 或 "Script Task 2" 执行并成功之后执行。
执行SSIS包并进行测试。
混合约束和表达式评估操作(表达式求值运算)
如果 SSIS 仍在运行则停止它。
双击 "Script Task 4" 和" Script Task 3" 之间的优先约束打开优先约束编辑器。修改多重约束为逻辑与。设置 求值运算(Evaluation Operation
) 为 "表达式和约束"(Expression and Constraint
)。确认"值"设置为"成功",表达式设置为 "@MyBool"
为了这个优先约束进行评估(运算),前面的任务必须执行成功,并且 SSIS 变量 "User::MyBool" 的值必须为 True。"MyBool"默认设置为False。
这个优先约束将永不会评估为True,因为必须是约束为True(执行成功,Success)和表达式(MyBool)为True。但是MyBool是False。这样最后不管脚本任务是否执行成功,都会阻止优先约束的评估。
尝试执行当前包,可以发现 "Script Task 3" 将永远不会执行。
重新打开 "Script Task 4" 和 "Script Task 3" 之间优先约束编辑器。修改"求值运算"为"表达式或约束"(Expression or Constraint
):
关闭编辑器,并运行SSIS包。这次"Script Task 3"将会执行。
"Script Task 3" 执行是因为连接到它的两个优先级约束都评估为True。很容易理解如何评估 "Script Task 2" 和 "Script Task 3" 之间的优先级约束。但是,"Script Task 4" 和 "Script Task 3" 之间的优先级约束如何评估?评估运算设置为“表达式或约束”,这意味着表达式或约束必须评估为True。如果两个都为True,则优先约束也将为True。但是OR条件至少需要一个表达式或约束条件来评估True。因为变量值设置为False,所以表达式 MyBool 的结果不为True。约束 —— 成功执行上一个任务 —— 评估为True。这就是允许执行 "Script Task 3" 的原因。
优先约束注释(Annotation)
在操作的过程中,你可能注意到:我们将"求值运算"从"表达式和约束"修改为"表达式或约束"的过程中,控制流中图画呈现在视觉上没有任何变化。(实际上,"求值运算" 只有修改 "约束" 的值时,才会在视觉上改变颜色)。
我们如何分辨其中的不同呢?可以借助于注释实现:点击优先约束选中它,然后按"F4"显示属性,可以看到第一个属性 "ShowAnnotation",将其设置为 "ConstraintOptions"。
ShowAnnotation 属性的 ConstraintOptions 设置显示:用于阐明优先级约束的评估操作(求值运算)的文本。
综合使用
编辑 "Script Task 2" 和 "Script Task 4" 的 Main()
函数代码如下:
public void Main()
{
// TODO: Add your code here
var sTaskName = Dts.Variables["TaskName"].Value.ToString();
var boxRes = MessageBox.Show("set "+sTaskName + " Succeed?", "确认", MessageBoxButtons.YesNo);
if (boxRes == DialogResult.Yes)
{
Dts.TaskResult = (int)ScriptResults.Success;
}
else
{
Dts.TaskResult = (int)ScriptResults.Failure;
}
}
该代码在每个脚本任务中创建任务成功(success)的提示框。编辑 "Script Task 4" 和 "Script Task 3" 之间的优先约束,设置求值运算为 "表达式和约束"(Expression and Constraint
),值为"失败",表达式为 "@MyBool"
编辑 "Script Task 2" 和 "Script Task 3" 之间的优先约束,设置求值运算为"表达式"(Expression
),表达式为"!@MyBool"
如下,是两个优先约束的 "ShowAnnotation" 属性都为 "ConstraintOptions" 显示的效果:
求值运算(Evaluation Operation
)设置为表达式,会导致 "ConstraintOptions" 显示为 "Completion and "。
"Script Task 3"执行之前会发生什么?
- 什么都不发生。当其他任务执行时,"Script Task 3"将执行。
- "Script Task 4" 或 "Script Task 2" 执行并成功后,将执行"Script Task 3"。
- "Script Task 4" 和 "Script Task 2" 执行并成功后,将执行"Script Task 3"。
- "Script Task 3" 将永远不会执行。
可以运行SSIS包测试下。
这是一个技巧问题(trick question
,诡计问题)。答案是4 —— "Script Task 3" 将永远不会执行。
下面修改 "MyBool" 值为 True,"Script Task 2" 和 "Script Task 3" 之间的表达式改为 "@MyBool"
其他"陷阱"(Gotcha
)
禁用 "Script Task 4",当执行SSIS包时,"Script Task 4" 将不执行,"Script Task 3" 也同样不会执行
为什么?MyBool为True,"Script Task 2"完成。"Script Task 4"跳过。当 "Script Task 4" 禁用后,控制流推断为 "成功"(Success)。这意味着"失败优先约束"将不会评估。
总结
本篇中,我们使用SSIS变量控制优先约束评估、检测多重约束,并查看了一个"陷阱(gotchas)"注意项。