【问题标题】:SSIS - Various number of columns to output to flat fileSSIS - 输出到平面文件的各种列数
【发布时间】:2017-02-25 02:02:04
【问题描述】:

我目前正在创建一个 SSIS,它将从数据库中收集数据并将其输出到单个逗号分隔的平面文件中。该文件将包含订单详细信息 文件格式为

Order#1 details (51 columns)
Order#1 header  (62 columns)
Order#2 details (51 columns)
Order#2 header  (62 columns)
etc...

订单标题有 62 列,订单详情有 51 列。我需要将它输出到一个平面文件,我遇到了一个问题,因为 SSIS 不处理不同的列。有人可以帮我吗,鉴于我的源是带有查询的 OLEDB 源,我如何创建脚本组件以输出到文件。

当前包如下所示:

  1. 获取所有订单的列表。将 orderid 作为变量传递。
  2. for 循环容器遍历每个 orderid,运行数据任务流以获取订单的订单详细信息。运行数据任务以获取订单标题。 我只是遇到了将每一行输出到平面文件的问题。

如果有人能提供帮助,我们将不胜感激。我已经为此苦苦挣扎了一个星期。如果有人可以让我从脚本组件代码的外观开始,我将不胜感激。

我已经添加了到目前为止的内容: http://imgur.com/a/yTxfH

这就是我的脚本的样子:

public void Main()
    {
        // TODO: Add your code here
        DataTable RecordType300 = new DataTable();
        DataTable RecordType210 = new DataTable();
        DataTable RecordType220 = new DataTable();
        DataTable RecordType200 = new DataTable();

        OleDbDataAdapter adapter = new OleDbDataAdapter();
        adapter.Fill(RecordType300, Dts.Variables["User:rec_type300"].Value);
        adapter.Fill(RecordType210, Dts.Variables["User::rec_type_210"].Value);
        adapter.Fill(RecordType220, Dts.Variables["User::rec_type_220"].Value);
        adapter.Fill(RecordType200, Dts.Variables["User::rec_type200"].Value);
        using (StreamWriter outfile = new StreamWriter("C:\\myoutput.csv"))
        {
            for (var i = 0; i < RecordType300.Rows.Count; i++)
            {
                var detailFields = RecordType300.Rows[i].ItemArray.Select(field => field.ToString()).ToArray();
               // var poBillFields = RecordType210.Rows[i].ItemArray.Select(field => field.ToString()).ToArray();
              //  var poShipFields = RecordType220.Rows[i].ItemArray.Select(field => field.ToString()).ToArray();
             //   var poHeaderFields = RecordType200.Rows[i].ItemArray.Select(field => field.ToString()).ToArray();
                outfile.WriteLine(String.Join(",", detailFields));
              //  outfile.WriteLine(string.Join(",", poBillFields));
              //  outfile.WriteLine(string.Join(",", poShipFields));
              //  outfile.WriteLine(string.Join(",", poHeaderFields));
            }
        }

        Dts.TaskResult = (int)ScriptResults.Success;

    }

但每次我运行它时,它都会出错。我在这里错过了什么吗?另外,我将如何在开始时创建一个文件只有 1 次。这意味着每次运行这个包时,它都会创建一个带有日期戳的文件,并每次都附加到它上面。下次运行包时,它将创建一个带有新日期戳的新文件,并根据订单号附加每个订单详细信息。

【问题讨论】:

  • 我认为你的剧本想法是正确的。考虑将标题和详细信息中的结果放入两个单独的数据表中。请参阅此链接作为如何填充和迭代它们的示例。 stackoverflow.com/a/14103080
  • @Sorrell。目前我确实有两个单独的数据表。我遇到的问题实际上是创建脚本。
  • 对于不完整的文件,通常的解决方法是将数据导出为 one 列,该列恰好包含一堆以逗号分隔的数据。您可以编写一个查询来生成和导出它,但这取决于您更喜欢 T-SQL 还是 C#。恕我直言,C# / Lookup 方法令人费解且不连贯。我更喜欢编写一个 SQL 查询来完成所有工作(高效)并导出它
  • 我喜欢@Nick.McDermaid 提出的想法。您可以使用 (ponumber, filetype, csvcontents (max varchar)) 创建一个表。那么您可能有 4 个 PO# 1 条目(#1_detail 文件类型、#2_bill 文件类型、#3)ship 文件类型、#4_header 文件类型)。然后在你的 SQL 中,ORDER BY PONUMBER, FILETYPE

标签: sql-server ssis etl ssis-2012


【解决方案1】:

此代码/方法尚未经过测试,但应该能让您很好地了解该做什么。

  1. 创建 2 个对象类型的 SSIS 变量,一个用于标题,一个用于详细信息。
  2. 创建 2 个Execute SQL 任务和 1 个Script Task,如下所述:
  3. 设置您的任务以处理完整的结果集,类似于这些图片(显示详细版本,对 Header 执行类似操作,但将结果映射到 Header 对象并将查询更改为指向标题表):
  4. 编辑您的脚本任务并允许DetailHeader 作为只读变量:
  5. 现在按照这些行编辑您的实际脚本(这是假设您正好有 1 个标题行的 1 个详细信息行):

using System.IO;
using System.Linq;
using System.Data.OleDb;

// following to be inserted into Main() function
DataTable detailData = new DataTable();
DataTable headerData = new DataTable();
OleDbDataAdapter adapter = new OleDbDataAdapter();
adapter.Fill(detailData, Dts.Variables["User::Detail"].Value);
adapter.Fill(headerData, Dts.Variables["User::Header"].Value);

using (StreamWriter outfile = new StreamWriter("myoutput.csv"))
{
    // we are making the assumption that 
    for (var i = 0; i < detailData.Rows.Count; i++)
    {
        var detailFields = detailData.Rows[i].ItemArray.Select(field => field.ToString()).ToArray();
        var headerFields = headerData.Rows[i].ItemArray.Select(field => field.ToString()).ToArray();
        outfile.WriteLine(string.Join(",", detailFields));
        outfile.WriteLine(string.Join(",", headerFields));
    }
}

【讨论】:

  • 谢谢。这真的很棒。但是,我不想从脚本中提取数据,因为我必须执行额外的查找。例如,在输出之前,我必须查找公司名称。
  • 如果我有它来执行 SQL 任务脚本,那么我将无法对列进行更改。
  • 在数据流中可以做的任何事情都可以用 SQL 和 C# 来完成。例如,您可以重组查询以连接到 Company 表以获取名称,而不是查找?如果是这样,那么该列是您的结果集的一部分。也可以使用 SQL 和/或 C# 进行推导和计算。
  • @Sorell 我已经更新了文件并添加了额外的 cmets。我厌倦了使用相同的逻辑,但它在脚本组件方面出错了。如果您有任何意见,请告诉我。特别是变量方面似乎存在问题。
  • 我做到了。我设法让这个工作。你的想法很有效。最后不得不修改代码。而是逐列获取。
【解决方案2】:

不是一个完整的答案,只是让你走上另一种方法的轨道

SELECT Type, OrderBy, Col
FROM
(
   SELECT 'D' As Type, Ord as OrderBy, 
   Col1 + ',' + CAST(Col2 AS VARCHAR(50)) + ',' + Col3 As Col
   FROM Details
   UNION ALL
   SELECT 'H' As Type, Ord as OrderBy,
   Col1 + ',' + CAST(Col2 AS VARCHAR(50)) + ',' + Col3 As Col + ',' + Col4
   FROM Header
) S
ORDER BY OrderBy, Type

它很难看,但只要将所有数据类型转换为 varchar 就可以工作

您可以将其封装在视图或存储过程中并从数据库中对其进行测试(在您进入 SSIS 部分之前)。您甚至可以使用 BCP.EXE 而不是 SSIS 导出它

这里有一个恰好包含此类数据的列:

 A,B,C
 D,E,F,G

从元数据的角度来看,始终存在一列

从 CSV 的角度来看,有可变列

【讨论】:

    猜你喜欢
    • 2010-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多