无需自定义编码 - 这是 SSIS 的所有开箱即用功能。
你的包裹大概是这样的
变量
创建变量来处理我们需要的东西。这些都是字符串数据类型,除了rsObject
- ColumnList 这将包含通过 FELC 填充的列列表
- CurrentFileName 这将基于表达式
@[User::PathOutput] + "\\" + @[User::SchemaName] + "_" + @[User::TableName] + ".csv"
- PathOutput 这是我们想要生成导出文件的地方。我使用 C:\ssisdata,但您需要使其适用于您的环境
- rsObject 这将保存执行 SQL 任务的结果集
- SchemaName 这将是架构名称,由 FELC 填充
- TableName 这是表名,通过 FELC 填写
连接管理器
有两个连接管理器:Source 和 ExportFile。
Source 是指向我的源数据库 (localhost\dev2014 msdb) 的 OLE DB 连接管理器。
ExportFile 是一个平面文件连接管理器,定义为单列 ColumnList,DT_STR 数据类型,8000 列宽,并使用 CRLF 列分隔符。另一件要注意的是,我在连接管理器上定义了一个表达式(右键单击连接管理器并选择属性)。这里我们将ConnectionString 分配给变量@[User::CurrentFileName]
执行 SQL 任务
此任务的目的是生成我们正在使用的数据集。我将使用 STUFF/FOR XML PATH “技巧”将多行连接成一行。我们将把所有列折叠成一行,其中包含 SchemaName、TableName 和逗号分隔的列名列表。运行以下查询以查看它生成的数据。
SELECT
S.name AS SchemaName
, T.name AS TableName
, (
SELECT
STUFF
(
(
SELECT
',' + C.name
FROM
sys.columns AS C
WHERE
C.object_id = T.object_id
ORDER BY
C.column_id
FOR XML PATH('')
)
, 1
, 1
, ''
)
) AS ColumnList
FROM
sys.schemas AS S
INNER JOIN
sys.tables AS T
ON S.schema_id = T.schema_id
ORDER BY
1,2;
您可以修改上述内容以过滤行数为零的位置,或者只生成所有表,然后不向客户端发送您不需要的文件。该解决方案留给您。
我指定执行 SQL 任务返回一个完整的结果集。我将结果推送到我们的变量@[User::rsObject]。
FELC 粉碎结果
我使用 ForEach 循环容器集来分解 ADO.NET 结果。源表是我们的@[User::rsObject]。在围绕数据集的每个循环中,我们将 @[User::SchemaName]、@[User::TableName]、@[User::ColumnList] 分配给 SSIS 变量
DFT 生成导出
此数据流任务旨在通过 OLE DB 源选择列列表变量,带有参数,并路由到平面文件目标。
OLE DB 源使用以下查询
SELECT CAST(? AS varchar(8000)) AS ColumnList
我将@[User::ColumnList] 映射到序数位置0。这将允许源查询“导入”变量的值。
平面文件目标使用我们的 ExportFile 连接管理器并将列 ColumnList 映射到文件中的唯一列。
比米尔
商业智能标记语言或 Biml 是一种描述 SSIS 包的 XML 方言。它使创建 SSIS 包变得更加容易,因为我可以给你这个代码来创建我上面描述的确切包。
你如何使用它?
- 下载BimlExpress
- 注册。它是免费的,但需要一个可以接收许可证密钥的电子邮件地址。
- 打开一个 SSIS 项目并右键单击该项目并添加新的 Biml 文件
- 将 BimlScript.biml 的内容替换为以下 Biml。
- 更新第 3 行以更改数据源以指向您的服务器和初始目录以匹配您的数据库
- 更新第 4 行以指向您希望生成 CSV 的位置
- 更新第 26 行以匹配文件夹位置(与第 6 步相同)
- 右击 BimlScript 会生成一个名为 SO_51195870.dtsx 的包
代码
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Connections>
<OleDbConnection ConnectionString="Data Source=localhost\dev2014;Initial Catalog=msdb;Provider=SQLNCLI11.1;Integrated Security=SSPI;Auto Translate=False;Packet Size=32767;" Name="Source" />
<FlatFileConnection Name="ExportFile" FileFormat="FFF Header File" FilePath="C:\ssisdata\Demo.csv" DelayValidation="true" />
</Connections>
<FileFormats>
<FlatFileFormat Name="FFF Header File" CodePage="1252" IsUnicode="false" >
<Columns>
<Column Name="ColumnList" DataType="AnsiString" Length="8000" Delimiter="CRLF" />
</Columns>
</FlatFileFormat>
</FileFormats>
<Packages>
<Package Name="SO_51195870" ConstraintMode="Linear">
<Connections>
<Connection ConnectionName="ExportFile">
<Expressions>
<Expression ExternalProperty="ConnectionString">@[User::CurrentFileName]</Expression>
</Expressions>
</Connection>
</Connections>
<Variables>
<Variable Name="SchemaName" DataType="String"></Variable>
<Variable Name="TableName" DataType="String"></Variable>
<Variable Name="ColumnList" DataType="String"></Variable>
<Variable Name="PathOutput" DataType="String">C:\ssisdata</Variable>
<Variable Name="CurrentFileName" DataType="String" EvaluateAsExpression="true">@[User::PathOutput] + "\\" + @[User::SchemaName] + "_" + @[User::TableName] + ".csv"</Variable>
<Variable Name="rsObject" DataType="Object" />
</Variables>
<Tasks>
<ExecuteSQL Name="SQL GetData" ConnectionName="Source" ResultSet="Full">
<Results>
<Result Name="0" VariableName="User.rsObject"/>
</Results>
<DirectInput>SELECT
S.name AS SchemaName
, T.name AS TableName
, (
SELECT
STUFF
(
(
SELECT
',' + C.name
FROM
sys.columns AS C
WHERE
C.object_id = T.object_id
ORDER BY
C.column_id
FOR XML PATH('')
)
, 1
, 1
, ''
)
) AS ColumnList
FROM
sys.schemas AS S
INNER JOIN
sys.tables AS T
ON S.schema_id = T.schema_id
ORDER BY
1,2</DirectInput>
</ExecuteSQL>
<ForEachAdoLoop Name="FELC Shred Results" SourceVariableName="User.rsObject">
<VariableMappings>
<VariableMapping Name="0" VariableName="User.SchemaName"/>
<VariableMapping Name="1" VariableName="User.TableName"/>
<VariableMapping Name="2" VariableName="User.ColumnList"/>
</VariableMappings>
<Tasks>
<Dataflow Name="DFT Generate Export" DelayValidation="true">
<Transformations>
<OleDbSource Name="OLESRC Query" ConnectionName="Source">
<DirectInput>SELECT CAST(? AS varchar(8000)) AS ColumnList</DirectInput>
<Parameters>
<Parameter Name="0" VariableName="User.ColumnList" />
</Parameters>
</OleDbSource>
<FlatFileDestination Name="DST File" ConnectionName="ExportFile"></FlatFileDestination>
</Transformations>
</Dataflow>
</Tasks>
</ForEachAdoLoop>
</Tasks>
</Package>
</Packages>
</Biml>
为什么引用的解决方案会失败
引用的解决方案不希望导出空记录集。它有明确的逻辑来测试空案例If reader.HasRows Then ...这也是提供的错误的来源。 finally 块中的 writer.Close() 是 Nothing,因此无法针对它调用 Close 操作。
避免异常的可能重写是
Finally
connection.Close()
If writer IsNot Nothing Then
writer.Close()
End If
End Try
也就是说,即使你去掉了有行检查,你仍然会得到一个空文件。
鳍
我真诚地推荐我概述的方法。我使用系统表来生成一组模式、表和列。该数据集用于构建外部文件。这是解决上述问题的无脚本 SSIS 方法。引用的 VB 方法没有这样做,它将完全重写该代码以使其如此。