在SSIS脚本组件中用C#将多行扁平文件合并为单条记录
解决SSIS脚本组件中扁平文件Header与Detail合并的问题
你现在遇到的核心问题是按行类型分组后,没法把Header和Detail对应起来——毕竟没有关联ID,分开的两组数据自然没法合并。其实这类Header+Detail结构的扁平文件处理,核心思路是缓存Header数据,遇到Detail时直接合并输出,如果是一个Header对应多个Detail,就先缓存所有Detail再和Header一起输出。下面给你两种常见场景的具体实现:
场景1:一个Header对应一个Detail(一一对应)
这种情况是扁平文件里每一个Header行后面跟着一个Detail行,我们只需要把Header的字段暂存起来,读到Detail时就把两者合并成一条输出记录。
脚本实现步骤:
- 先在SSIS脚本组件的输出列里,添加所有需要的Header字段和Detail字段(比如
HeaderID、HeaderName、DetailAmount、DetailDate等)。 - 打开脚本编辑器,声明类级别的变量来存储Header数据(这些变量会在整个脚本执行期间保留值):
// 类级变量,用于暂存Header字段 private string _headerID; private string _headerName;
- 在
CreateNewOutputRows方法里编写读取逻辑:
public override void CreateNewOutputRows() { // 替换成你的扁平文件路径 string flatFilePath = @"C:\Data\YourFlatFile.txt"; using (StreamReader sr = new StreamReader(flatFilePath, Encoding.Default)) { string line; while ((line = sr.ReadLine()) != null) { // 假设每行第一个字符是行类型标识:H=Header,D=Detail string recordType = line.Substring(0, 1).Trim(); if (recordType == "H") { // 解析Header行,根据你的文件格式调整截取位置和长度 _headerID = line.Substring(1, 8).Trim(); _headerName = line.Substring(9, 20).Trim(); // 其他Header字段同理解析 } else if (recordType == "D") { // 解析Detail行 string detailAmount = line.Substring(1, 10).Trim(); string detailDate = line.Substring(11, 10).Trim(); // 其他Detail字段同理解析 // 创建输出行,合并Header和Detail数据 Output0Buffer.AddRow(); Output0Buffer.HeaderID = _headerID; Output0Buffer.HeaderName = _headerName; Output0Buffer.DetailAmount = decimal.Parse(detailAmount); // 注意类型转换 Output0Buffer.DetailDate = DateTime.Parse(detailDate); // 映射所有输出列 } } } }
场景2:一个Header对应多个Detail(一对多,合并为单条记录)
如果是一个Header后面跟着多条Detail,需要把所有Detail的内容合并到一个字段里(比如用逗号分隔),再和Header一起输出。
脚本实现步骤:
- 在输出列里添加Header字段和一个用于存储合并后Detail的字段(比如
MergedDetails,类型为字符串)。 - 声明类级变量:
private string _currentHeaderID; private StringBuilder _detailBuilder;
- 在
CreateNewOutputRows方法里编写逻辑:
public override void CreateNewOutputRows() { string flatFilePath = @"C:\Data\YourFlatFile.txt"; using (StreamReader sr = new StreamReader(flatFilePath)) { string line; while ((line = sr.ReadLine()) != null) { string recordType = line.Substring(0, 1).Trim(); if (recordType == "H") { // 如果之前有未输出的Header和Detail,先输出 if (_detailBuilder != null && _detailBuilder.Length > 0) { Output0Buffer.AddRow(); Output0Buffer.HeaderID = _currentHeaderID; Output0Buffer.MergedDetails = _detailBuilder.ToString(); // 重置StringBuilder _detailBuilder.Clear(); } // 存储当前Header数据 _currentHeaderID = line.Substring(1, 8).Trim(); // 初始化StringBuilder用于缓存Detail _detailBuilder = new StringBuilder(); } else if (recordType == "D") { // 解析Detail内容,这里假设取除了行类型外的所有内容 string detailContent = line.Substring(1).Trim(); // 追加到StringBuilder,用逗号分隔(可自定义分隔符) if (_detailBuilder.Length > 0) { _detailBuilder.Append(", "); } _detailBuilder.Append(detailContent); } } // 处理最后一组Header和Detail,避免遗漏 if (_detailBuilder != null && _detailBuilder.Length > 0) { Output0Buffer.AddRow(); Output0Buffer.HeaderID = _currentHeaderID; Output0Buffer.MergedDetails = _detailBuilder.ToString(); } } }
关键注意事项
- 字段解析要准确:一定要根据你的扁平文件实际格式调整
Substring的起始位置和长度,避免截取错误。如果是分隔符文件,也可以用Split方法拆分字段。 - 处理边缘情况:比如遇到没有对应Detail的Header,或者没有对应Header的Detail,可以添加判断逻辑,比如跳过这类行,或者输出到错误行里。
- 编码问题:如果你的扁平文件有特殊编码(比如UTF-8、GB2312),一定要在
StreamReader里指定对应的编码,避免乱码。
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

