【问题标题】:SSIS Import data that is NOT columnar into SQLSSIS 将非列式数据导入 SQL
【发布时间】:2020-04-27 02:47:33
【问题描述】:

我是 SSIS 的新手,需要一些帮助才能开始。我有几份来自我们的大型机的报告。报告不是柱状格式。日期记录在顶部,然后可能有一些初始数据,然后可能还有更多。所以我需要阅读每一行,看看文本的内容,并确定我是否需要数据或移动到下一行。

这是我要导入 SQL 表的报告的一个非常粗略的示例。

DATE:  01/08/2020                   FACILITY NAME                             PAGE1

                 REVENUE USAGE                     FOR ACCOUNTING PERIOD 02
   ----TOTAL----  ----TOTAL----  ----OTHER----  ----INSURANCE----  ----INSURANCE2----  

SERVICE CODE - 123456789  DESCRIPTION:  WIDGETS
CURR                 2,077
 IP          0.0000      3     2,345     0.00       
                     143
 OP          0.0000      2     1,231     0.00

YTD                    5
   IP         0.0000
                       76 
   OP         0.0000   
etc . . . .. .
SERVICE CODE

在服务代码之后,数据将开始像上面一样重复。这是报告的基本思想。

我想获取日期,然后是服务代码、描述、当前 IP 数量、当前 IP 美元、当前 OP 数量、当前 OP 美元、YTD IP 数量、YTD IP 美元、 YTD OP 量,YTD OP 美元。 .然后重复。

澄清一下,我并不是要任何人为我做这件事。我想学习如何做到这一点。我已经研究过如何做到这一点,但我看到的每个示例都谈到了使用 CSV、选项卡或 Excel 文件来做到这一点。我没有那种类型的文件,所以我在问我需要看什么。我目前使用 Monarch 来格式化文件,但我想再次了解有关 SSIS 的更多信息,这是一种完美的学习方式。要求供应商重做报告不是一种选择,而且我想学习如何做到这一点。谢谢,我只是想把它弄出来。

任何帮助将不胜感激。
罗杰

【问题讨论】:

  • 简而言之,您可能需要使用脚本转换。这不是我们可以用我们所拥有的一点点帮助的事情,而要求我们完成整个事情将是一个很大的要求。我建议开始并查找主题,当您遇到困难时,提出相关问题。
  • 如果我是你,我会联系拥有来自大型机的报告的人,并询问是否有可能以更易使用的格式获取数据。最喜欢的数据来自表,因此将数据重新格式化两次只是为了将其重新放入表中似乎效率很低。否则,正如建议的那样,您将需要使用脚本任务或类似任务以及 StreamReader 来处理文件。
  • 是的,但是它必须与平面文件源相关联,然后是目标,您必须配置输入和输出,所有这些(至少对我而言)都是很多事情为相同的最终结果。如果您在脚本任务中完成所有操作,则不必这样做,您可以从流阅读器中读取并在同一个位置写入服务器,这样简单得多(在我看来)。所以我的意思是,我不认为这是错误的选择,只是不同的选择。
  • 似乎只是意见冲突然后@GarethD。 :)
  • 简短答案。这可以用 SSIS 来完成吗 - 可能非常困难。您可以在 SSIS 中执行此操作吗?可能不会。使用具有结构良好的数据和少量额外转换逻辑的 SSIS 来学习和实施任务并不太难。但这种方法远不止于此。正如已经建议的那样,在您了解(并定义)如何将报表转换为数据库架构之后,第一步是使用您知道的语言编写预处理器。

标签: sql sql-server text import ssis


【解决方案1】:

如 cmets 中所述,您可以使用脚本任务执行此操作。基本步骤是:

  1. 定义一个DataTable 来存储您的数据。
  2. 使用StreamReader 阅读您的报告。
  3. 使用条件组合、String Methodsparsing 来处理此问题,以从相关行中提取相关字段:
  4. 使用SqlBulkCopy将DataTable写入数据库

以下内容将进入脚本任务的 Main 方法中:

//Define a table to store your data 
var table = new DataTable
{
    Columns = 
    { 
        { "ServiceCode", typeof(string) }, 
        { "Description", typeof(string) }, 
        { "CurrentIPVolume", typeof(int) },
        { "CurrentIPDollar,", typeof(decimal) },
        { "CurrentOPVolume", typeof(int) },
        { "CurrentOPDollar", typeof(decimal) },
        { "YTDIPVolume", typeof(int) },
        { "YTDIPDollar,", typeof(decimal) },
        { "YTDOPVolume", typeof(int) },
        { "YTDOPDollar", typeof(decimal) } 
    }
};

var filePath = @"Your File Path";
using (var reader = new StreamReader(filePath))
{
    string line = null;
    DataRow row = null;

    // As YTD and Curr are identical, we will need a flag later to mark our position within the record
    bool ytdFlag= false; 

    //Loop through every line in the file 
    while ((line = reader.ReadLine()) != null)
    {
        //if the line is blank, move on to the next
        if (string.IsNullOrWhiteSpace(line)
            continue;

        // If the line starts with service code, then it marks the start of a new record
        if (line.StartsWith("SERVICE CODE"))
        {
            //If the current value for row is not null then this is
            //not the first record, so we need to add the previous 
            //record to the tale before continuing              
            if (row != null)
            {
                table.Rows.Add(row);
                ytdFlag= false; // New record, reset YTD flag
            }
            row = table.NewRow();

            //Split the line now based on known values:
            var tokens = line.Split(new string[] { "SERVICE CODE - ", "DESCRIPTION: "}, StringSplitOptions.None);

            row[0] = tokens[0];
            row[1] = tokens[1]; 
        }

        if (line.StartsWith("CURR"))
        {
            //Process the row --> "CURR                 2,077"
            //Not sure what 2,077 is, but this will parse it
            int i = 0;
            if (int.TryParse(line.Substring(4).Trim().Replace(",", ""), out i))
            {
                //Do something with your int
                Console.WriteLine(i);
            }

        }

        if (line.StartsWith(" IP"))
        {
            //Start at after IP then split the line into the 4 numbers
            var tokens = line.Substring(3).Split(new [] { " "}, StringSplitOptions.RemoveEmptyEntries);

            //If we have gone past the CURR record, then at to YTD Columns
            if (ytdFlag)
            {
                row[6] = int.Parse(tokens[1]);
                row[7] = decimal.Parse(tokens[1]);
            }
            //Otherwise we are still in the CURR section:
            else
            {
                row[2] = int.Parse(tokens[1]);
                row[3] = decimal.Parse(tokens[1]);
            }
        }
        if (line.StartsWith(" OP"))
        {
            //Start at after OP then split the line into the 4 numbers
            var tokens = line.Substring(3).Split(new [] { " "}, StringSplitOptions.RemoveEmptyEntries);

            //If we have gone past the CURR record, then at to YTD Columns
            if (ytdFlag)
            {
                row[8] = int.Parse(tokens[1]);
                row[9] = decimal.Parse(tokens[1]);
            }
            //Otherwise we are still in the CURR section:
            else
            {
                row[4] = int.Parse(tokens[1]);
                row[5] = decimal.Parse(tokens[1]);
            }

            //After we have processed an OP record, we must set the YTD Flag to true.
            //Doesn't matter if it is the YTD OP record, since the flag will be reset
            //By the next line that starts with SERVICE CODE anyway
            ytdFlag= true;
        }
    }
}

//Now that we have processed the file, we can write the data to a database
using (var sqlBulkCopy = new SqlBulkCopy("Your Connection String"))
{
    sqlBulkCopy.DestinationTableName = "dbo.YourTable";

    //If necessary add column mappings, but if your DataTable matches your database table
    //then this is not required

    sqlBulkCopy.WriteToServer(table);
}

这是一个非常简单的示例,与完成的文章相去甚远,我几乎没有做过测试,但它应该为您提供可以如何完成的要点,并帮助您开始一种可能的解决方案。

它绝对可以被清理和重构,但我试图尽可能清楚地说明发生了什么,而不是试图编写有史以来最高效的代码。它还应该(希望)证明这是一个巨大的痛苦,并且非常小的报告会改变一些事情,比如一个额外的空间是“OP”会破坏整个事情。

因此,我再次重申,如果您可以获取标准平面文件格式的数据,每条记录一行,您应该这样做。然而,我确实很感激有时这些事情是你无法控制的,而且我过去不得不编写像这样非常丑陋的导入例程,所以如果你不能以可消费的格式获取数据,我会感到很痛苦。

【讨论】:

  • 哇,这太棒了。谢谢你,这对我有很大帮助!!!我期待在周末进行这项工作。再次谢谢你!!!
  • 再次感谢您。这正是我开始所需要的。我看到我在看了更多之后还有很多工作要做。每个“部分”有 4 行要评估。Current_Total、IP、OP、YTD_Total、YTD_IP、YTD_OP
猜你喜欢
  • 1970-01-01
  • 2016-11-26
  • 2018-06-30
  • 2017-09-20
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 2017-12-02
  • 1970-01-01
相关资源
最近更新 更多