这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战
翻译参考
本文主要参考翻译自 The Stairway to Integration Services 系列文章的原文 Flexible Source Locations - Level 16 of the Stairway to Integration Services,目的在于对 SSIS 有一个全面清晰的认识,所有内容在原文的基础上进行实操,由于版本差异、个人疑问等多种原因,未采用完全翻译的原则,同时也会对文中内容进行适当修改,希望最终可以更有利于学习和了解 SSIS,
感谢支持!
在本文中,我们将利用 SSIS 参数、变量和 Foreach 循环容器从动态数量的源中加载数据。通过参数和变量动态生成连接字符串或源路径,循环增量加载某一位置的多个数据源...
准备数据并配置好增量加载SSIS包
获取和了解数据
在开始之前,请单击 此链接(andyweather.com/data/Weathe…) 下载从我的 Farmville 气象站收集的源数据。将文件解压缩到任意位置,推荐将测试数据放入 SSIS解决方案 文件夹中。
每个 MonthYear 文件夹都包含一个名为 TH 的子文件夹。每个 TH 文件夹都包含一个名为 sensor1-all.csv 的文件。这些文件表示在 2008年12月至2009年4月 之间收集的温度和湿度数据。这些文件是累积的 —— 2009年2月(February)文件包括 2008年12月(December) 文件中的所有数据加上 2008年12月(December)至2009年2月(February) 之间添加的记录,2009年4月(April) 文件中包括 2008年12月(December) 文件中的所有数据以及 2008年12月(December)至2009年4月(April) 之间添加的记录。所有三个文件的记录都始于如下所示的记录:
Date,Time,Min T,Max T,Average T,Min H,Max H,Average H,Comfort zone,Min DP,Max DP,Average DP,Min HI,Max HI,Average HI,Low Batt
2008-12-25,19:00,8.5,10.9,9.71,32,36,33,2,-6.0,-5.0,-5.71,--,--,--
2008-12-25,20:00,6.3,8.5,7.21,36,40,38,2,-6.0,-5.0,-5.95,--,--,--
2008-12-25,21:00,5.3,6.7,6.37,39,43,40,0,-6.0,-6.0,-6.00,--,--,--
由于这些文件的内容,最好使用增量加载策略提供服务。我们在以下内容中介绍了增量加载:
SSIS学习使用三:Integration Services增量加载之新增数据 SSIS学习使用四:Integration Services增量加载之更新数据 SSIS学习使用五:Integration Services增量加载之删除数据
原文地址:
进行操作之前,了解你的数据非常重要。
这是从气象站收集的数据。你多久阅读一次早报或观看晚间新闻,或听到这样的声音:“昨天的高温,我们错了。不是71°F,实际上是70.5°F。”这可能会发生,但我从未见过。
我们的数据是“仅前进”(forward-only)的。既不会有更新,也不会有删除。由于数据的性质,我们将仅加载新行。使用的增量负载策略将反映出这一点,此处将使用的设计模式可在 “SSIS学习使用三:Integration Services增量加载之新增数据” 中找到。
添加查找转换
在 SQL Server 2012 Data Tools – BI 中打开 "FirstSSIS" 项目。然后打开 LoadWeatherData.dtsx SSIS包。双击 "DFT Stage Temperature and Humidity" 数据流任务打开编辑器。
点击从 “FFSrc Temperature and Humidity” 平面文件源适配器连接到 “OLEDest Stage Temperature” OLE DB目标适配器 的数据流路径,然后删除数据流路径,如图所示。
从SSIS工具箱拖拽一个 "查找转换"(Lookup Transformation) 到数据流界面。从 “FFSrc Temperature and Humidity” 平面文件源适配器连接一个 数据流路径(data flow path) 到新的 查找转换,如图所示。
双击 “查找” 转换以打开 “查找转换编辑器”。编辑器将打开 “常规” 页面。在此处要进行的唯一更改是 “指定如何处理无匹配项的行” 下拉菜单 —— 希望将值更改为“将行重定向到无匹配输出”,如图所示。
图9
单击 “连接” 页面,并确保在 “OLE DB连接管理器” 下拉列表中选择了 WIN-FR5GRQSCDPO.WeatherData 连接管理器。将下面的语句添加到 “使用SQL查询的结果” 文本框中,如图所示。
Select [Date], [Time]
From dbo.StageTemperature
图10
单击 Columns 页面,然后将 Available Input Columns 网格中的 Date列 映射到 Lookup Columns 网格中的 Date列,并将 Available Input Columns 网格中的 Time列 映射到 Lookup Columns 网格中的 Time列。
图11
单击"确定"按钮,完成对Lookup转换的配置。
转换处理的过程
“Lookup转换是如何工作的?”很高兴你能这样问!我们将 "查找" 配置为使用完全缓存(默认缓存模式),这意味着查找转换将使用其获取的缓存数据填充 RAM 块。在图9中,你可以看到Cache Mode设置以及我们打算使用的连接类型:OLE DB Connection Manager。图10提供了连接详细信息,从将要使用的连接数据库WIN-FR5GRQSCDPO.WeatherData的连接管理器开始,我们有两种方法可以访问连接管理器公开的数据库中的数据:
- 使用表或视图。
- 使用SQL查询的结果。
如果选择表或视图,则整个表的内容(或视图返回的内容)都将在缓存操作期间通过查找全部存储在 RAM 中。如果使用 OLE DB连接管理器 连接类型,并且为查找配置“完全缓存”(Full Cache),则 查找缓存操作将在“数据流任务”的 PreExecute 事件期间发生。
在 Columns 页面(图11)上,我们配置查找比较哪些列用来检查匹配的行。我们将“可用输入列”的Date列映射到“可用查找列”的ate列,并将“可用输入列”的Time列映射到“可用查找列”的Time列。这意味着,包含Date和Time的两列的值必须都相等才能触发匹配。
我们在 “常规” 选项卡上配置了 “指定如何处理无匹配项的行” 下拉列表,将“不匹配的行”发送到 "无匹配查找输出"(NoMatch lookup output)。
切记:了解你的数据。sensor1-all.csv 文件中每个 date/hour 组合只有一个条目。如果 Date和Time 匹配,则该行已存在于 WeatherData.dbo.StageTemperature 表中。由于只需要加载新行,所以将忽略这些匹配的行。
查找无匹配输出路径和OLEDB目标
下图显示了 “输入输出选择” 窗口,当我们将输出从 “查找”转换 拖动到 “OLEDest Stage Temperature”OLE DB目标适配器 时,将显示该窗口:
选择 "Lookup No Match Output",并点击"确定",完成数据流路径连接。
WeatherData.dbo.StageTemperature表中可能要先清除下数据。连接到 本系列上一篇 中创建的 WeatherData 数据库的SQL Server实例上。
执行如下的脚本以完成清理操作:
Use WeatherData
go
Truncate Table StageTemperature
清除目标staging表后,执行包。数据流应类似下图所示。
现在,重新执行该SSIS包。现在,数据流应该看起来类似下图所示。
请注意,原始的106行已通过 “FFSrc Temperature and Humidity”平面文件源适配器 从文件加载到数据流中,并且相匹配的行位于 WeatherData.dbo.StageTemperature 表中,因此 "Lookup转换" 经过 "查找无匹配输出" 未发送任何行。
现在可以重新执行此SSIS程序包。它只会加载当前未存储在目标数据库表中的行。
循环(Loop It!)
添加项目参数
回想上一节 SSIS学习使用十五:SSIS参数概述,我们有一个名为 $Package::SourceFilePath 的包参数,并且该参数值用于设置 “FFCM Temperature and Humidity”平面文件连接管理器 的 ConnectionString 属性。
接下来,将对如何管理此 ConnectionString 进行一些更改。
首先,打开 Package Parameters 选项卡并删除 SourceFilePath 参数,如图所示。
接下来,通过在解决方案资源管理器中,双击 Project.params 打开 Project Parameters,如图所示。
单击 "添加参数" 按钮,并使用以下属性值配置参数:
- Name: SourceFolder
- Data type: String
- Value:
<the path where you decompressed the WeatherData_Dec08_Apr09.zip file> - Sensitive: False
- Required: False
- Description: The folder containing the weather data files.
单击全部保存按钮,然后关闭 Project Parameters 窗口。
添加并配置Foreach循环容器
返回到 LoadWeatherData.dtsx SSIS包的控制流。将一个 Foreach循环容器 拖到Control Flow画布上,
将 “DFT Stage Temperature and Humidity”数据流任务 拖到 Foreach循环容器 中。
重命名 Foreach循环容器 为“FOREACH Temperature File”。如图所示。
我们需要配置Foreach循环容器,以在data文件夹的子文件夹中搜索 *.csv 文件。
双击“FOREACH Temperature File”foreach循环容器,打开其编辑器,如图所示:
单击 "集合"(Collection) 页面。默认的枚举器(enumerator)是 “Foreach文件枚举器”(Foreach File Enumerator),这就是此时需要的枚举器,如图所示。
还有其他类型的枚举器可用。但现在不需要了解,不过希望你能知道这一点。并且,还可以开发自己的自定义foreach枚举器(custom foreach enumerator),这比我们在本文中要介绍的内容还要多。
每个枚举器(无论是内置的还是自定义的)都可以公开能在运行时动态更新的属性。这些属性通过 枚举器表达式(Enumerator Expressions) 暴露出来,并且通过单击 Enumerator 属性正下方的 Expressions文本框 中的省略号可以访问 Enumerator Expressions。
单击省略号打开“属性表达式编辑器”,如图所示。
在本例中,需要使 “Foreach文件枚举器” 的文件夹(Directory属性)动态化。在 “属性” 下拉列表中选择 “Directory” 属性,然后在 “表达式”文本框 中单击省略号,以打开“表达式生成器”。
在 “表达式构建器” 窗口左上方的列表框中,展开 “变量和参数” 虚拟文件夹。单击 $Project::SourceFolder 项目参数(project parameter),并将其拖到“表达式”文本框中。单击"Evaluate Expression"按钮,以检查 $Project::SourceFolder 参数的值,如图所示。
单击“确定”按钮,关闭Expression Builder。Property Expressions Editor可能如下图所示。如果没有显示 —— 发现表达式并不总是显示 —— 再次单击省略号,然后再次单击OK按钮以重新关闭Expression Builder,将会起作用。
单击"确定"按钮,关闭属性表达式编辑器。
如果展开在“集合”页面上的“Enumerator”属性下面的“Expressions”属性,现在应该看到 Directory 属性已动态耦合到 $Project::SourceFolder 项目参数。
将“文件”(Files)值从“.”(默认值)更改为“*.csv”,以将枚举器配置为仅返回CSV(逗号分隔值)文件。要检索每个CSV文件的完整路径,请选中“完全限定名称”选项。
最后,选中“遍历子文件夹”复选框,以便枚举器将“向下进入”到子文件夹中以搜索CSV文件,如图所示。
Fully qualified—— 完全限定名称Name and extension—— 名称和扩展名Name only—— 仅名称
Traverse subfolders—— 遍历子文件夹
当前页面上发生了什么?基于当前的配置,Foreach文件枚举器将转到指定的目录(现在已动态链接到$Project::SourceFolder项目参数),并返回在指定文件夹和子文件夹中找到的CSV文件的完整路径。
每个CSV文件的完整路径将一次返回一个,并且将执行 "Foreach循环容器" 的内容。
另一种理解方式是:容器将为找到的每个CSV文件循环一次。每次容器循环时,将执行循环的内容。
我们需要一个变量来存储所标识的每个CSV文件的完整路径,因为打算在每次循环迭代时增量加载所标识的CSV文件的内容。
可以在 “变量映射”(Variable Mappings) 页面上创建此 SSIS 变量。单击 Variable 下拉列表,然后单击“<New Variable…>”,如图所示。
“添加变量”窗口将会显示。将变量名称设置为 SourceFileName。确保将 Container 设置为Package(LoadWeatherData)作用域。默认的命名空间是User,默认的数据类型是String,并且不需要为变量提供默认值,如图所示:
Index值默认为0,这是检测到的CSV文件的完全限定路径返回的合适值,如图所示。

配置文件连接管理器的ConnectionString
最后一步是更改 “FFCM Temperature and Humidity”平面文件连接管理器 的 ConnectionString 属性,使其使用现在的名为 User::SourceFileName 的新变量。
单击连接管理器,然后按F4键以显示Properties,如图所示。

单击 "Expressions"值文本框 中的省略号以打开“属性表达式编辑器”,如图所示。

此处显示的是当前的配置,因为删除了SourceFilePath包参数,所以不再有效。
单击“表达式”文本框中的省略号,显示 “表达式生成器” 窗口。删除表达式文本框中的值 (@[$Package::SourceFileName])。展开 Variables and Parameters 虚拟文件夹,并将 User::SourceFileName 拖到 Expression文本框 中,如图所示。

单击"确定"按钮,关闭“表达式生成器”窗口。现在,Property Expressions Editor应该如下所示。

单击"确定"按钮,关闭属性表达式编辑器。
设置断点
现在已经准备好进行测试。在此操作之前,先在 “DFT Stage Temperature and Humidity”数据流任务 上设置一个断点。
右键单击“DFT Stage Temperature and Humidity”数据流任务,然后单击“编辑断点…”(Edit Breakpoints),如图所示:

显示“设置断点”窗口时,点击 “容器收到OnPostExecute事件时断开”(Break when the container receives the OnPostExecute event) 选项,如图所示。

选择 “当容器接收到OnPostExecute事件时中断” 选项将允许每次迭代执行数据流任务时 —— 针对由"Foreach循环容器"找到的每个CSV文件 —— 中断执行。因为我们将完整的文件路径从Foreach循环容器中读取到 User::SourceFileName 变量中,然后使用该值动态更新平面文件连接管理器,所以断点将在数据流任务处理完每个文件的内容后中断执行。
注意,最后一句话有很多信息。可以通过不同的方式拆解它,查看处理的每个步骤。
- “FOREACH Temperature File” Foreach循环容器 转到
$Project::SourceFolder项目参数的值指定的文件夹。 - 对于指定的每个CSV文件(一次一个文件),在此文件夹(或下方)找到的所有CSV文件的完整路径都被读入
User::SourceFileName变量。 User::SourceFileName变量控制 “FFCM Temperature and Humidity”平面文件连接管理器 的ConnectionString属性。- “DFT Stage Temperature and Humidity”数据流任务针对每个识别的CSV文件执行一次。
- “FFSrc Temperature and Humidity”平面文件源适配器已耦合到 “FFCM Temperature and Humidity”平面文件连接管理器,该管理器的目标是已标识的CSV平面文件。
- “DFT Stage Temperature and Humidity”数据流任务将增量加载来自被识别的CSV文件中的数据。
希望这些会有所帮助和有意义。这并不是一个微不足道的过程。
运行测试
按F5键,开始在调试器中执行包。当断点被“命中”时,控制流将显示如下图

由于断点的配置 —— 在PostExecute事件上中断 —— “DFT Stage Temperature and Humidity”数据流任务 已经执行完。数据流选项卡将显示如图所示

请注意,平面文件源适配器读取了1,983行,但仅加载了1,877行。这是为什么? Dec08数据(106行)先前已加载到表中。此数据来自Apr09文件。
请记住,此数据流仅加载新行 —— 先前未加载的数据。 1,877 + 106 = 1,983。
引用 福格霍格·莱格霍恩 的话来说:“……数字不会说谎。”
To quote Foghorn Leghorn, “…figures don’t lie.”
调试器的一项很酷的功能是"监视窗口"(Watch Windows)。可以使用Locals(局部变量)窗口在执行期间检查变量值的状态。要打开Locals,请单击 Debug-> Windows-> Locals,如图所示。
To reach e Locals wind, click Debug -> Windows -> Locals

显示“局部变量”窗口后,展开“变量”节点(Variables node)。滚动直到找到 User::SourceFileName 变量。注意,该值是位于 Apr09 文件夹中的 sensro1-all.csv 文件,如图所示:

按F5键继续执行。当再次到达断点时,Dec08文件已被处理。请注意,没有行加载到目标表。
Locals窗口验证 User::SourceFileName 变量的值包含 Dec08 文件夹,这意味着 “FFCM Temperature and Humidity”平面文件连接管理器 正在通过 ConnectionString 动态属性表达式动态连接到 Dec08 数据文件,如图所示:

再次按F5键,我们前进到Feb09的数据。
最后一次按F5键完成执行。控制流应如图所示:

测试成功!
总结
在本文中,我们利用 SSIS参数、变量和Foreach循环容器 从大量来源加载数据。Foreach循环在此处允许我们从三个源进行加载,但是也可以实现轻松地从 30 个源或未知数量的源进行数据的加载。