案例背景与需求介绍

之前做过一个美国的医疗保险的项目,保险提供商有大量的文件需要发送给比如像银行,医疗协会,第三方服务商等。比如像与银行交互的 ACH 文件,传送给协会的 ACH Credit 等文件。这些文件格式在美国都是开放的,通用的,可以直接到相关网站下载。也就是说像银行,协会等他们接受这种固定格式的文件,读取数据,读取公司编号进行业务来往或者记录。我当时就是直接在网上搜索到一个 PDF 格式的文件说明,大概有10来页,就是告诉你这个格式是如何定义,应该如何来处理的。

那么这种文件并非像我们通常看到的一个文件所有的行都是遵循一种格式,这种文件分为很多 Section:
  1. File Header/Trailer
  2. Batch Header/Trailer
  3. 还有细节的交易数据等
会发现第1,2,3-5,6,7 行它们的格式都不一样,不同于我们之前的平面文件输出,在同一种格式下批量输出。
它们的文件格式说明就明确规定了某一行的输出有多少列,每列应该是什么内容,宽度,格式等等都严格的定义了。

案例演示与讲解

下面我使用 Adventure Works DW 2012 数据中的数据模拟输出类似于这种格式的平面文件。
比如下方是我的一个文件示例,第一行是单独的一个 Section,第二行也是,自第三行起到倒数第二行的格式是相同的,最后一行又是独立的一个输出格式。那么这个文件就是由 4 个 Section 组成。
 
假设格式的定义如下所示:
一般来说,对于 Header 或者 Trailer 中数据通常以描述性数据为主。比如像 Header 1 中的标题部分 -  ADVENTUREWORKS EMPLOYEE INFORMATION  这些都是固定的长度。但同时也有动态变化的内容,比如 Header 1 中的文件输出日期,以及 Header 2 中的员工数量。像 Trailer 部分,一般也是这种描述性的数据为主。
那么如何来输出这种格式的数据,很显然我们不能直接指定一个数据源表,然后将表中的内容给查询出来然后控制好长度直接输出,因为几个不同 Section 部分的格式是不一样的。我们的做法是,将 Header 1 和 Header 2 这样占少量行的数据拼接成一个整体输出;而对于像 Content 部分细节数据则使用数据库表操作自然输出。
 
同时,还要解决一个问题,如何让这不同格式的 Section 能够输出到同一个文件?这些在下面的步骤中都将能看到。
下面这三部分的数据将为 OLE DB Source 提供数据查询结果 -

对于 Header 1 和 Header 2 的处理

创建存储过程,此存储过程输出一个两行单列的表数据。
IF OBJECT_ID('T006_GET_EMPLOYEE_FILE_HEADERS') IS NOT NULL
DROP PROCEDURE T006_GET_EMPLOYEE_FILE_HEADERS
GO CREATE PROCEDURE T006_GET_EMPLOYEE_FILE_HEADERS
AS
BEGIN
SET NOCOUNT ON DECLARE @EMPLOYEE INT
SELECT @EMPLOYEE = COUNT(*)
FROM T006_EMPLOYEE SELECT 'FILE CREATED DATE:' + -- Description
CONVERT(VARCHAR(12),GETDATE(),110) + -- File Created Date
SPACE(20) + -- 80 spaces
'**********' +
' ADVENTUREWORKS EMPLOYEE INFORMATION ' + -- Company Report Name
'**********' +
SPACE(95) AS HEADER
UNION
SELECT 'TOTAL EMPLOYEES:' +
CONVERT(VARCHAR(10),@EMPLOYEE) +
SPACE(184-LEN(CONVERT(VARCHAR(10),@EMPLOYEE))) AS HEADER
END
GO

对于 Trailer 的数据处理

创建存储过程,输出一个一行一列的表数据。
IF OBJECT_ID('T006_GET_EMPLOYEE_FILE_TRAILERS') IS NOT NULL
DROP PROCEDURE T006_GET_EMPLOYEE_FILE_TRAILERS
GO
CREATE PROCEDURE T006_GET_EMPLOYEE_FILE_TRAILERS
AS
BEGIN
SET NOCOUNT ON
SELECT REPLACE(SPACE(92),' ','*') +
' ADVENTUREWORKS ' +
REPLACE(SPACE(92),' ','*') AS TRAILER
END

对于 Content 的数据处理

直接使用查询即可,然后在输出文件的时候确保各列输出的格式与长度。
SELECT FirstName +' '+LastName AS CustomerName,
Title,
HireDate,
BirthDate,
EmailAddress,
Phone,
MaritalStatus
FROM T006_EMPLOYEE

在控制流中,需要由3个数据流包构成,分别操作 Header 部分的输出,Content 部分的输出以及 Trailer 部分的输出。
连接管理器 CM_FF_EMPLOYEE_HEADER 接受来自于 T006_GET_EMPLOYEE_FILE_HEADERS 存储过程的输出。
连接管理器 CM_FF_EMPLOYEE_CONTENT 接受 SELECT 查询结果,同时要注意控制各列按指定宽度输出。
连接管理器 CM_FF_EMPLOYEE_TRAILER 接受存储过程 T006_GET_EMPLOYEE_FILE_TRAILERS 的输出。
但是要注意,它们指向的都是同一个目标平面文件。当然,马上就会有人问:那么不会出现后一个文件将前一个文件覆盖掉的后果吗?
这就是本案例处理的关键点所在 - 在 CM_FF_EMPLOYEE_HEADER 目标编辑器中选中 Overwrite data in the file - 覆盖已存在的文件。
但是在后面两个输出中将不会选择这个选项,那么后面两个输出 Content 和 Trailer 将会紧接着 Header 写入到同一个文件中形成一个整体。
 最终的输出效果如下 - 

处理平面文件还需要了解这几篇文章

更多 BI 文章请参看 BI 系列随笔列表 (SSIS, SSRS, SSAS, MDX, SQL Server)  如果觉得这篇文章看了对您有帮助,请帮助推荐,以方便他人在 BIWORK 博客推荐栏中快速看到这些文章。

微软BI 之SSIS 系列 - 带有 Header 和 Trailer 的不规则的平面文件输出处理技巧的更多相关文章

  1. 微软BI 之SSIS 系列 - 使用 Script Component Destination 和 ADO.NET 解析不规则文件并插入数据

    开篇介绍 这一篇文章是 微软BI 之SSIS 系列 - 带有 Header 和 Trailer 的不规则的平面文件输出处理技巧 的续篇,在上篇文章中介绍到了对于这种不规则文件输出的处理方式.比如下图中 ...

  2. 微软BI 之SSIS 系列 - 再谈Lookup 缓存

    开篇介绍 关于 Lookup 的缓存其实在之前的一篇文章中已经提到了 微软BI 之SSIS 系列 - Lookup 组件的使用与它的几种缓存模式 - Full Cache, Partial Cache ...

  3. 微软BI 之SSIS 系列 - 在 SSIS 中导入 ACCESS 数据库中的数据

    开篇介绍 来自 天善学院 一个学员的问题,如何在 SSIS 中导入 ACCESS 数据表中的数据. 在 SSIS 中导入 ACCESS 数据库数据 ACCESS 实际上是一个轻量级的桌面数据库,直接使 ...

  4. 微软BI 之SSIS 系列 - MVP 们也不解的 Scrip Task 脚本任务中的一个 Bug

    开篇介绍 前些天自己在整理 SSIS 2012 资料的时候发现了一个功能设计上的疑似Bug,在 Script Task 中是可以给只读列表中的变量赋值.我记得以前在 2008 的版本中为了弄明白这个配 ...

  5. 微软BI 之SSIS 系列 - 使用 Script Task 访问非 Windows 验证下的 SMTP 服务器发送邮件

    原文:微软BI 之SSIS 系列 - 使用 Script Task 访问非 Windows 验证下的 SMTP 服务器发送邮件 开篇介绍 大多数情况下我们的 SSIS 包都会配置在 SQL Agent ...

  6. 微软BI 之SSIS 系列 - 数据仓库中实现 Slowly Changing Dimension 缓慢渐变维度的三种方式

    开篇介绍 关于 Slowly Changing Dimension 缓慢渐变维度的理论概念请参看 数据仓库系列 - 缓慢渐变维度 (Slowly Changing Dimension) 常见的三种类型 ...

  7. 微软BI 之SSIS 系列 - Lookup 中的字符串比较大小写处理 Case Sensitive or Insensitive

    开篇介绍 前几天碰到这样的一个问题,在 Lookup 中如何设置大小写不敏感比较,即如何在 Lookup 中的字符串比较时不区分大小写? 实际上就这个问题已经有很多人提给微软了,但是得到的结果就是 C ...

  8. 微软BI 之SSIS 系列 - Execute SQL Task 中的 Single Row 与 Full Result Set 的处理技巧

    开篇介绍 Execute SQL Task 这个控件在微软BI ETL 项目中使用的频率还是非常高的,也是大部分入门 SSIS 初学者最早接触到的几个控制流控件. 我们通常使用 Execute SQL ...

  9. 微软BI 之SSIS 系列 - Merge, Merge Join, Union All 合并组件的使用以及Sort 排序组件同步异步的问题

    开篇介绍 SSIS Data Flow 中有几个组件可以实现不同数据源的数据合并功能,比如 Merger, Merge Join 和 Union All.它们的功能比较类似,同时也比较容易混淆,下面是 ...

随机推荐

  1. poj2019 二维RMQ模板题

    和hdu2888基本上一样的,也是求一个矩阵内的极值 #include<iostream> #include<cstring> #include<cstdio> # ...

  2. MVC开发中的常见错误-07-“System.IO.DirectoryNotFoundException”类型的未经处理的异常在 mscorlib.dll 中发生

    “System.IO.DirectoryNotFoundException”类型的未经处理的异常在 mscorlib.dll 中发生 其他信息: 未能找到路径“F:\Users\home\Docume ...

  3. .NetCore下使用IdentityServer4 & JwtBearer认证授权在CentOS Docker容器中运行遇到的坑及填坑

    今天我把WebAPI部署到CentOS Docker容器中运行,发现原有在Windows下允许的JWTBearer配置出现了问题 在Window下我一直使用这个配置,没有问题 services.Add ...

  4. System.getenv()和System.getProperty() 的区别

    1.System.getenv() 方法是获取指定的环境变量的值.它有两种方法,一种是接收参数为任意字符串,当存在指定环境变量时即返回环境变量的值,否则返回null.另外一种是不接受参数,那么返回的是 ...

  5. 开始写博客,学习Linq(4)

    应该是可以敲代码了,Linq是.NET Framework3.5的功能,该版本的框架同时发布了新增的和更新了得类库,也为C#和VB.NET语言提供了新版本的编译器.Linq的功能支持源于编译器和类库, ...

  6. 解决Delphi7的自带的UTF-8编码转换函数BUG

    Delphi7及其以下版本的 VCL 只支持 Ansi, 所以... WideString 与 UTF8String (定义与 AnsiString 相同) 并没有办法正确的在 VCL 中显示 Del ...

  7. 注册表键值明明存在OpenSubKey始终返回null,解决方案

    先上代码及实例 RegistryKey rsg = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Macromedia\FlashPaper Pri ...

  8. Codeforces 739C Alyona and towers 线段树

    Alyona and towers 这个题写起来真的要人命... 我们发现一个区间被加上一个d的时候, 内部的结构是不变的, 改变的只是左端点右端点的值, 这样就能区间合并了. 如果用差分的话会简单一 ...

  9. Codeforces 535D - Tavas and Malekas

    535D - Tavas and Malekas 题目大意:给你一个模板串,给你一个 s 串的长度,告诉你 s 串中有 m 个模板串并告诉你,他们的其实位置, 问你这样的 s 串总数的多少,答案对1e ...

  10. 【Java】 剑指offer(58-2) 左旋转字符串

      本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部 ...