如何使用SSIS组件将同ID多行合并为含不同列值的单行
在SSIS中实现相同主键多行数据的列合并
我懂你现在的需求——把相同Mat(PK)的多行数据合并成一行,把各个字段里的非空值对应填充到目标列里。既然已经用SQL搞定了,那我来给你拆解下用SSIS组件怎么实现,有两种实用的方法:
方法一:使用聚合转换(Aggregate Transformation)
这是最直接的方法,适合你这种同一分组下每个字段仅存在一个非空值的场景:
- 先在数据流中添加数据源组件(比如OLE DB Source),读取你的输入数据。
- 拖入聚合转换,将数据源的输出连接到聚合转换。
- 打开聚合转换编辑器:
- 把
Mat(PK)设置为分组依据(Group By),确保按主键分组。 - 对
Activity、EntryDate、Grade这三个字段,分别选择Max或Min聚合函数——因为NULL在聚合计算中会被忽略,而同一分组里每个字段只有一个非空值,Max/Min会精准取到这个有效值。 - 可以保持每个聚合字段的别名和原字段名一致,方便后续映射到目标表。
- 把
- 最后把聚合转换的输出连接到目标组件(比如OLE DB Destination),就能得到你想要的合并后结果了。
方法二:使用脚本组件(Script Component)作为转换
如果后续遇到更复杂的合并场景(比如同一字段有多个非空值需要拼接),脚本组件会更灵活。针对你的需求,实现步骤如下:
- 在数据流中添加脚本组件,选择「转换(Transformation)」类型。
- 连接数据源到脚本组件,打开脚本编辑器:
- 在输入列面板,勾选所有需要处理的列:
Mat(PK)、Activity、EntryDate、Grade。 - 在输出列面板,添加和输入列对应的输出列(名称、类型保持一致)。
- 切换到「脚本」选项卡,编辑脚本(以C#为例):
- 在输入列面板,勾选所有需要处理的列:
using System.Collections.Generic; using Microsoft.SqlServer.Dts.Pipeline.Wrapper; using Microsoft.SqlServer.Dts.Runtime.Wrapper; [Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute] public class ScriptMain : UserComponent { // 用字典存储每个Mat(PK)对应的合并后数据 private Dictionary<string, MergedRow> mergedRecords; public override void PreExecute() { base.PreExecute(); mergedRecords = new Dictionary<string, MergedRow>(); } public override void Input0_ProcessInputRow(Input0Buffer Row) { string matId = Row.MatPK; if (!mergedRecords.ContainsKey(matId)) { // 第一次遇到该主键,初始化合并行 mergedRecords[matId] = new MergedRow { MatPK = matId, Activity = Row.Activity_IsNull ? null : Row.Activity, EntryDate = Row.EntryDate_IsNull ? null : Row.EntryDate, Grade = Row.Grade_IsNull ? null : Row.Grade }; } else { // 已有该主键的记录,填充非空值 var existingRow = mergedRecords[matId]; if (!Row.Activity_IsNull) existingRow.Activity = Row.Activity; if (!Row.EntryDate_IsNull) existingRow.EntryDate = Row.EntryDate; if (!Row.Grade_IsNull) existingRow.Grade = Row.Grade; } } public override void PostExecute() { base.PostExecute(); // 遍历字典,输出所有合并后的行 foreach (var mergedRow in mergedRecords.Values) { Output0Buffer.AddRow(); Output0Buffer.MatPK = mergedRow.MatPK; // 处理Activity字段 if (!string.IsNullOrEmpty(mergedRow.Activity)) Output0Buffer.Activity = mergedRow.Activity; else Output0Buffer.Activity_IsNull = true; // 处理EntryDate字段 if (mergedRow.EntryDate.HasValue) Output0Buffer.EntryDate = mergedRow.EntryDate.Value; else Output0Buffer.EntryDate_IsNull = true; // 处理Grade字段 if (!string.IsNullOrEmpty(mergedRow.Grade)) Output0Buffer.Grade = mergedRow.Grade; else Output0Buffer.Grade_IsNull = true; } } // 自定义类存储合并后的行数据 private class MergedRow { public string MatPK { get; set; } public string Activity { get; set; } public DateTime? EntryDate { get; set; } public string Grade { get; set; } } }
- 保存脚本后,将脚本组件的输出连接到目标组件即可。
这两种方法都能完美实现你给出的输入输出示例,比如Mat=12的三行数据,合并后会得到Activity=Dev、EntryDate=01/01/2000、Grade=Eng+8的单行结果。
内容的提问来源于stack exchange,提问作者Ayari HoussemEddine
相关产品推荐
相关产品推荐

