【问题标题】:Exporting empty tables from multiple SQL tables to csv format将多个 SQL 表中的空表导出为 csv 格式
【发布时间】:2018-12-14 04:55:45
【问题描述】:

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

当我遵循解决方案时: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 target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) 在 System.Reflection .RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] 参数, CultureInfoculture, Boolean skipVisibilityChecks) 在 System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] 参数, CultureInfoculture ) 在 Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTATaskScriptingEngine 的 System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] 修饰符, CultureInfo 文化, String[] namedParams) .ExecuteScript()

【问题讨论】:

  • 重申:您想要创建一个仅包含标题行/列名称的平面文件?不用担心数据类型或类似的东西?
  • 客户真的想要这个,还是更喜欢您的表的实际 SQL/DDL/数据定义语言?
  • 您好,客户希望创建一个平面文件,该文件仅包含不包含数据的表的标题行/列名称
  • 你为什么不做一个数据库备份,因为你想要所有的表(包括那些有数据的......或者你的意思是表但不是数据这些?),还是使用 GUI?
  • 我会问为什么你的数据库中有 500 个空表。这似乎有点奇怪。除非您知道它们是什么数据类型,否则 csv 作为数据工具是无用的。如果你想要的只是列名,为什么不使用 sys.columns 编写一个简单的查询呢?

标签: sql-server vb.net ssis


【解决方案1】:

无需自定义编码 - 这是 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 包变得更加容易,因为我可以给你这个代码来创建我上面描述的确切包。

你如何使用它?

  1. 下载BimlExpress
  2. 注册。它是免费的,但需要一个可以接收许可证密钥的电子邮件地址。
  3. 打开一个 SSIS 项目并右键单击该项目并添加新的 Biml 文件
  4. 将 BimlScript.biml 的内容替换为以下 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 ...这也是提供的错误的来源。 finally 块中的 writer.Close() 是 Nothing,因此无法针对它调用 Close 操作。

避免异常的可能重写是

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

也就是说,即使你去掉了有行检查,你仍然会得到一个空文件。

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

【讨论】:

  • 嗨,当我使用 Biml 代码时,出现以下错误:
  • 错误:项目一致性检查失败。检测到以下不一致:SO_51195870.dtsx 的 ProtectionLevel 与项目不同。
  • 嗨,谁能帮忙,我被上面的错误困住了,不知道该怎么办?
  • 项目一致性检查失败 => 您需要在第 14 行 ProtectionLevel="EncryptSensitiveWithPassword" 在 ConstraintMode... 之后和 &gt; 之前添加以下内容
  • 开始项目一致性检查...错误:项目一致性检查失败。检测到以下不一致:SO_51195870.dtsx 的 ProtectionLevel 与项目不同。构建完成 -- 1 个错误,0 个警告
【解决方案2】:

听起来您想编写所有表格的脚本。操作方法如下:

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

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

然后在下一步中选择文件位置,然后你就完成了。

【讨论】:

  • 嗨,这不会给我平面文件。正如我所说,我必须提供所有表格的摘录,其中包括空白表格。按照stackoverflow.com/questions/6216486/… 上的解决方案,我可以导出包含数据的表,但是当它尝试导出空白表的数据时,我得到了错误(在我的原始帖子中有详细说明)
  • 定义平面文件?它实际上包含什么?格式是什么?
  • csv 文件,只有空表的标题。即“column1”、“column2”、“column3”
  • 所有表及其列名的 csv 文件?
  • 我肯定会接受scsimon的推荐!!我想不出更简单或更稳定的方法来做这种事情。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-29
  • 2018-08-14
  • 1970-01-01
  • 1970-01-01
  • 2020-12-05
  • 1970-01-01
  • 2020-11-14
相关资源
最近更新 更多