将多个SQL表中的空表导出为CSV格式

时间:2018-07-05 16:11:24

标签: sql-server vb.net ssis

如何导出空白表(即仅标题)以及包含数据的表。使用空白表格的原因是我的客户想要导入表格结构,即标题,以便将来在需要时可以使用它。

在以下情况下遵循解决方案:Exporting data from multiple SQL tables to different flat files using SSIS Script Task时出现以下错误:

  

错误:System.Reflection.TargetInvocationException:调用的目标引发了异常。 ---> System.NullReferenceException:对象引用未设置为对象的实例。在ST_97b3989b700a41f1ad54fb2abd27b891.vbproj.ScriptMain.Main()处-内部异常堆栈跟踪的结尾处-在System.RuntimeMethodHandle._InvokeMethodFast(对象目标,Object []参数,SignatureStruct&sig,MethodAttributes methodAttributes,RuntimeTypeReflectle typeOwner)处。 .System.Reflection.RuntimeMethodInfo.Invoke(对象obj,BindingFlags invokeAttr,活页夹活页夹,Object []参数,CultureInfo文化),位于Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTATaskScriptingEngine的System.RuntimeType.InvokeMember(字符串名称,BindingFlags bindingFlags,活页夹活页夹,对象目标,Object []提供的Args,ParameterModifier []修饰符,CultureInfo文化,String []命名为Paraams) .ExecuteScript()

2 个答案:

答案 0 :(得分:1)

不需要自定义编码-这是SSIS的所有现成功能。

您的包裹看起来像这样

Execute SQL Task to FELC with Dataflow

变量

创建变量来处理我们所需要的。除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;

您可以修改上面的内容以过滤行数为零的位置,或者仅生成所有表,然后不向客户端发送不需要的文件。该解决方案留给您。

我指定Execute SQL Task返回完整的ResultSet。我将结果放入我们的变量@ [User :: rsObject]。

FELC切碎结果

我使用了一个ForEach循环容器设置来粉碎ADO.NET结果。源表是我们的@ [User :: rsObject]。在围绕数据集的每个循环中,我们将@ [User :: SchemaName],@ [User :: TableName],@ [User :: ColumnList]

分配给SSIS变量

DFT生成导出

该数据流任务旨在通过带有参数的OLE DB源选择列列表变量,并路由到平面文件目标。

enter image description here

OLE DB源使用以下查询

SELECT CAST(? AS varchar(8000)) AS ColumnList

我将@ [User :: ColumnList]映射到顺序位置0。这将允许源查询“导入”变量的值。

平面文件目标使用我们的ExportFile连接管理器,并将列ColumnList映射到文件中的唯一列。

Biml

商业智能标记语言或Biml是描述SSIS包的XML方言。因为我可以为您提供此代码来创建上面已描述的确切包,所以它使创建SSIS包变得容易得多。

您如何使用它?

  1. 下载BimlExpress
  2. 注册。它是免费的,但是需要一个可以接收许可证密钥的电子邮件地址。
  3. 打开一个SSIS项目,然后右键单击该项目并添加新Biml文件
  4. 用下面的Biml替换BimlScript.biml的内容。
  5. 更新第3行以将数据源更改为指向您的服务器,并更改“初始目录”以匹配您的数据库
  6. 更新第4行以指向您想要生成CSV的位置
  7. 更新第26行以匹配文件夹位置(与步骤6相同)
  8. 右键单击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 ...,这也是所提供错误的来源。最后一块中的writer.Close()为Nothing,因此无法对其执行Close操作。

为了避免该异常,可能会进行重写

    Finally
        connection.Close()
        If writer IsNot Nothing Then
            writer.Close()
        End If
    End Try

也就是说,即使您删除了具有行检查功能,您仍然会得到一个空文件。

Fin

我真诚地推荐我概述的方法。我使用系统表来生成模式,表和列的集合。该数据集用于构建外部文件。这是解决上述问题的无脚本SSIS方法。引用的VB方法不会 这样做,这将完全重写该代码。

答案 1 :(得分:0)

这听起来像是要脚本化所有表。这是操作方法:

右键单击数据库>任务>生成脚本

enter image description here

然后遵循GUI。具体来说,您要在第二步中选择Tables个对象:

objects

然后在下一步中选择文件位置,然后完成操作。