[译]Stairway to Integration Services Level 4 - 更新数据

在本文中, 我们说下增量更新数据:即将数据源中更新了的数据替换掉目标表中对应的数据.

更新代码

操作之前我们先把目标表e (dbo.Contact). 的数据改掉

Use AdventureWorks
go
Update dbo.Contact
 Set MiddleName = ‘Ray‘
 Where MiddleName Is NULL

打开 My_First_SSIS_Project. 点击  Data Flow 标签. 我们把Level 3的项目文件修改下.双击 Lookup Transformation 打开 Lookup Transformation Editor:


图 1

点击Columns 页面.

在前篇文章中, 我们映射了Available Input Columns和Available Input Columns的Email字段进行内联匹配.

在前一篇文章中我们没有勾选任何复选框.  如果把Lookup Transformation 当做 join看待, 选了这些字段就好像是在Select 子句里面增加字段 .  全选(点上面的Name) :

 
图 2

全选以后如图3 . Output Alias 列是就是 Available Lookup Columns输出列,类似Join以后返回的列. 我喜欢在添加前缀 “LkUp_” 或者 “Dest_” 这样方便区分来自 OLE DB Source 和 Lookup Transformation字段. 如果列名相同SSIS会后面加个“(1)”.   下图是添加了“LkUp_”前缀的截图:

图 3

现在让我们回顾一下 .

我们把Person.Contact 表中的记录载入Data Flow ,然后与 Lookup Transformation 中载入的 dbo.Contact进行记录匹配. 如果记录未匹配,则进行No Match Output 输出. 接着改动 Lookup Transformation 的配置, 如果发现匹配行,就输出  Email, FirstName, LastName, 和 MiddleName 列.

现在拖一个 OLE DB Command Transformation 和 Conditional Split Transformation . 点击  Lookup Transformation然后把蓝色的 Data Flow Path拖到 Conditional Split:

 
图 4

因为之前Lookup No Match Output 已经拖到 Contact , 所以只剩下Lookup Match Output ,这次拖到 Conditional Split就没提示选择 .Lookup Transformation 的No Match Output 和 Match Output .除了数据内容外,还有其他不同,但是最要的是字段不同.

右击OLE DB Source adapter 与 Lookup Transformation之间的Data Flow Path:

图 5

点击 Metadata 页,显示如下:

6

这些列来自OLE DB Source ,关掉这个 Data Flow Path 然后右击 OLE DB Destination (Contact) 与 Lookup Transformation之间的Data Flow Path,Metadata 页显示如下:

图 7

上一篇文章我们看过这个. Lookup Transformation的No Match 输出和输入的metadata其实是一模一样的.  也就是说如果没有匹配,只是简单把输入的字段直接输出.

这个章节我们改动了Lookup Transformation配置,因此匹配的记录Metadata会有所不同 : 目标表的字段会附加上去 .右击 Conditional Split Transformation 和Lookup Transformation 之间的 Data Flow Path . Metadata显示如下.

图 8

因为之前选择字段的时候我们采用的别名,因此很容易的看到附加字段.

还记得在上篇文章中,我们配置了 No Match Output,但并未从被查询的表中返回字段么? 因为增量添加记录不需要这些字段,不过我们现在需要用来对比字段值.

在SSIS中进行变更检测

打开 Conditional Split Transformation  可以看到两个虚拟目录: Variables 和 Columns:

图 9

点开 图9的 Columns 目录. 我们准备比较 FirstName, LastName, 和 MiddleName 字段.

先来比较 FirstName 字段. 点击 FirstName 然后拖到下面的列表中 :

图 10

松开鼠标以后你会发现 刚拖过去的FirstName因为验证失败而变红. 为什么会验证失败? 条件必须进行布尔运算 .但是FirstName是字符值,所以未进行判断. 错误提示如下:

 
图 11

右上角是条件表达式语句

SSIS 表达式语句有点难学,你可以看下我以前写的博文,应该对你有所帮助.

我要检查 FirstName  不等于 LkUp_FirstName. 在表达式区域点开 Operators 虚拟目录然后选择 unequal 操作符:

图 12

点击 Unequal 操作符,然后拖到 FirstName 字段右边:

图 13

接着把, LkUp_FirstName 拖过去 :

图 14

由于现在表达式计算结果为布尔值,所以整个条件表达式又变为黑色.

因为我们没有改过FirstName字段的值,所以当我们执行测试的时候. FirstName判断值总为False(我们只改了MiddleName 值) . 接着把其他几个字段也放进去判.最后把 Case 1 改名为 Updated Rows. 如下图

 
图 21

注意,每新建一个条件(condition) . Conditional Split Transformation 就会生成一个新的Output.用来传送数据

其中还有个 Default Output Name 如下图, 如果没有条件被匹配,那么记录会从这个output走

图 23

关掉Conditional Split Transformation ,然后拖动蓝色路径到 OLE DB Command. 选择Updated Rows 输出路径 :

图 24

现在你的Data Flow 应该显示如下:

 
图 25

我们用OLE DB Command Transformation 来对目标表进行更新操作. 双击打开OLE DB Command Transformation , 在Connection Manager 里面选择(local).AdventureWorks ,然后在 Manager Component Properties 标签的 SqlCommand  属性中输入以下SQL语句

Update dbo.Contact
  Set FirstName = ?
, MiddleName = ?
, LastName = ?
 Where Email = ?

图 26

接着我们还要映射参数占位符( parameter placeholders  就是问号(?)) ,点击 Column Mappings 标签:


图 27

? 标记是以0开始的数组. 也就是说  Param_0 对应第一个问号,Param_1  代表第二个 ,以此类推. 我们把相对应的字段都拖到参数进行映射 .

图 28

关掉OLE DB Command. 现在 Data Flow Task 应该和下图一样:

图 29

按 F5 测试下结果:

图 30

报错了…点开Process 标签.发现一些错误. 不过读起来比较困难.

图 31

如果我们可以右击错误,然后复制文本:

图 32

错误信息如下:

[Conditional Split [2]] Error: The expression "(FirstName != LkUp_FirstName) || (MiddleName != LkUp_MiddleName) || (LastName != LkUp_LastName)" on "Conditional Split.Outputs[Updated Rows]" evaluated to NULL, but the "Conditional Split" requires a Boolean results. Modify the error row disposition on the output to treat this result as False (Ignore Failure) or to redirect this row to the error output (Redirect Row).  The expression results must be Boolean for a Conditional Split.  A NULL expression result is an error.

错误的原因是我们表达式产生了NULL值. 表达式里面只要有一个比较是NULL, 那结果就不会是布尔值 Ture 或 False .

让我们来看看 Person.Contact里面哪个字段有空值:

Use AdventureWorks
go
Select *
 From Person.Contact
 Where FirstName Is Null

Select *
 From Person.Contact
 Where MiddleName Is Null

Select *
 From Person.Contact
 Where LastName Is Null

执行这些语句以后发现l 8,499 行的MiddleName 是空值. 其实就是我们之前更改的那些字段.

让哦们来解决这个问题. 通过IsNull() 函数来判断MiddleName是否空值,返回布尔结果. 语句更新如下:

(FirstName != LkUp_FirstName) || ((ISNULL(MiddleName)?"Humperdinck": MiddleName) != (ISNULL(LkUp_MiddleName) ? "Humperdinck": LkUp_MiddleName)) || (LastName != LkUp_LastName)

图 33

有个重要的地方注意下:“Humperdinck” 永远是个无效值.  如果源表中的MiddleName 由Null更新成了Humperdinck . 这时候 (ISNULL(MiddleName) ? "Humperdinck" : MiddleName)  结果是Humperdinck . 而 (ISNULL(LkUp_MiddleName) ? "Humperdinck" : LkUp_MiddleName)) 的结果也是Humperdinck. 表达式根本无法检测不同.

我用“Humperdinck” 当做 middle name是因为我喜欢 The Princess Bride 这个片子. 实际操作的话我会组合数字,字母及一些很难碰到的字符组合来做匹配. 

按F5再测试下:

 
图 34

测试成功..不过我们发现更新耗时了一分三十七秒 :

图 35

为什么执行花了这么长时间? 主要OLE DB Command执行语句花费时间较长. 为什么? 因为OLE DB Command  一次只更新一行. 像游标一样.

批量更新 Set-Based Updates

有没有方法避免这种单行(row-based)更新的模式? 让我们看看怎么处理.把 OLE DB Command删掉.然后托个  OLE DB Destination 代替它:

 
图 36

把OLE DB Destination 更名为“StageUpdates”.  双击打开 . 确保选了 “(local).AdventureWorks”和 “Table or View – Fast Load”.

新建表格 :

 
图 37

CREATE TABLE [StageUpdates] (
    [FirstName] nvarchar(50),
    [LastName] nvarchar(50),
    [Email] nvarchar(50),
    [MiddleName] nvarchar(50)
)

注意要映射字段:


图  38

点击 Mappings 页:

图 39

因为Available Destination Columns和 Available Input Columns的Metadata一样,所以字段已经自动匹配.

点击确认以后如图 40:

图 40

接着我们在Data Flow Task 下面拖个 Execute SQL task ,把StageUpdates表里面的记录更新到dbo.Contact :

图 41

双击 Execute SQL Task把 Name 属性改为 “Apply Staged Updates” .  Connection 属性选择 “(local).AdventureWorks”. 然后在 SQLStatement 属性里面贴入以下语句:

Update dest
 Set dest.FirstName = stage.FirstName
  , dest.MiddleName = stage.MiddleName
  , dest.LastName = stage.LastName
 From dbo.Contact dest
   Join dbo.StageUpdates stage
    On stage.Email = dest.Email

再改动以下dbo.Contact 表, 然后执行SSIS包:

Use AdventureWorks
go
Update dbo.Contact
 Set MiddleName = ‘Ray‘
 Where MiddleName Is NULL


图 42

Data Flow task :

图 43

执行时间已改善!

图 44

我们还需要处理以下StageUpdates 表, 执行之前我们先把记录清掉. 避免执行的时候数据重复导入. 在托一个 Execute SQL Task 到 Control Flow 然后连接 Data Flow Task:

图 45

双击Execute SQL Task 配置信息如下:

 
图 46

再执行一次 :

图 47

图 48

至此增量更新搞定.

原文地址: http://www.sqlservercentral.com/articles/Stairway+Series/76390/

资源:

点此下载项目文件

时间: 2024-08-29 00:13:15

[译]Stairway to Integration Services Level 4 - 更新数据的相关文章

[译]Stairway to Integration Services Level 16 – Flexible Source Locations (多文件导入)

介绍 在本文中我们将利用SSIS参数,变量 以及 Foreach Loop Container 从多个源动态导入数据. 开始前我们先下载一些数据.WeatherData_Dec08_Apr09.zip  解压以后我们看到有三个目录数据 Figure 1 每个月年目录包含一个子目录 TH.每个TH 目录包含文件 sensor1-all.csv.  这些文件是 December 2008 至 April 2009 温度和湿度数据. February 2009 的文件包括December 2008 至

[译]Stairway to Integration Services Level 12 - 高级日志配置

介绍 本文中,我们将结合之前学习的时间冒泡,日志记录,以及复制模型.建立一个自定义的SSIS包日志模型. SSIS Task事件回顾    Reviewing SSIS Task Events 在做实验之前我们更改一下 Precedence.dtsx SSIS 包的设置. 把 Precedence.dtsx SSIS 包的 DisableEventHandlers 属性改为True Figure 2 屏蔽内置日志   Disable Built-In Logging 首先我们要移除已经存在的日志

[译]Stairway to Integration Services Level 9 - Control Flow Task Errors

介绍 在本文中,我们会实验 MaximumErrorCount和ForceExecutioResult 故障容差属性,并且还要学习Control Flow task errors, event handlers 和 containers 的联系 关于 SSIS Task Errors 打开 Precedence.dtsx 包. 你的Control Flow 显示如下: 图 1 再做测试前我们先调整两个优先约束.   Script Task 4 和 Script Task 3  调整如下: 图 2

[译]Stairway to Integration Services Level 18 – 部署和执行

介绍 在本文中,我们要创建一个SSIS Catalog 实例,部署我们的项目,并且运行 weather data loader 包. SSIS 2012 部署模型   SSIS 2012 Deployment Models SQL Server 2012 Integration Services 支持两种部署模型: 包部署模型  Package Deployment Model 项目部署模型  Project Deployment Model 包部署模型是向后兼容的,支持SSIS 2012以前的

[译]Stairway to Integration Services Level 3 - 增量导入数据

让我们打开之前的项目:My_First_SSIS_Project_After_Step_2.zip 之前项目中我们已经向dbo.contact 导入了19972行,如果再次执行包会重复导入,让我们来解决这个问题. 增量导入目标 (Incremental Load Goals) 在我们批量处理之前,先来明确下增量导入的目标: 如果数据源中有新纪录,我们要把这些记录导入目的地. 如果数据源中有记录变更,我们要把之前导入目的地的相关记录更新. 如果数据源中的记录被删除,我们要把之前导入目的地的相关记录

[译]Stairway to Integration Services Level 6 - SSIS 工作流管理基础

简介 在之前的章节中,我们学习了增量载入数据. 本文中.我们通过优先约束(Precedence Constraints)来管理SSIS的工作流. 添加一个SSIS包 图 1 将新建的Package1.dtsx 改为 Precedence.dtsx  : 图 3 添加 Script Task 拖个 Script Task 到Control Flow: 图 5 Script Task估计是SSIS 里面最强大的组件了.你可以创建很多功能. 同样的,你能通过Script Task 控制SSIS工作流.

[译]Stairway to Integration Services Level 15 – SSIS 参数回顾

介绍 在本文中我们会研究SSIS变量姐妹: SSIS 变量. 我们会演示参数配置,通过包参数管理动态属性值,然后会演示SSIS包执行的时候参数怎么被配置的. SSIS Parameters 101 SSIS参数和SSIS变量很像.  在SSIS 2012里面 变量和参数是可以互换的. 不过有重要的不同点: SSIS包开始执行以后,参数是只读的. 参数的作用域为项目或者包级别. 参数有 Sensitive 属性. 参数有 Required 属性. 因为参数在SSIS包执行的之后参数是只读的.所以参

[译]Stairway to Integration Services Level 10 - 高级事件活动

介绍 在前一篇文章中我们介绍了故障容差相关的 MaximumErrorCount 和 ForceExecutionResult 属性.  同时我们学习了SSIS Control Flow task errors, containers, 和event handlers联系 . 本篇中我们关注事件行为. 我们用两种方法操纵日志传递(冒泡)行为. 同时也介绍父子模式(Parent-Child pattern )并且演示事件在父子模式中的行为. 关于 SSIS 任务事件 About SSIS Task

[译]Stairway to Integration Services Level 13 -SSIS 变量回顾

介绍 在前一篇中我们组合了已经学过的事件冒泡 event bubbling, 日志记录 logging, 和父子模型 Parent-Child pattern 建立了自定义的SSIS包日志记录. 本文中, 我们会将我们的解决方案升级至 SQL Server 2012 Integration Services 并且展示 SSIS变量 (SSIS variables), 变量(variable configuration), 以及通过表达式处理动态值 (dynamic value managemen