【问题标题】:Import data from excel into multiple tables将数据从excel导入多个表
【发布时间】:2011-04-09 12:12:30
【问题描述】:

我正在构建一个离线 C# 应用程序,它将从电子表格中导入数据并将它们存储在我创建的 SQL 数据库中(在项目内部)。通过一些研究,我已经能够使用一些可以将静态表导入到与工作表中的列布局完全相同的数据库中的代码

我要做的是让特定的列根据名称转到正确的表。这样我就可以正确设计数据库,而不仅仅是一个巨大的表来存储所有内容。

下面是我用来将几个静态字段导入到一个表中的代码,我希望能够将导入的数据拆分为多个。

最好的方法是什么?

public partial class Form1 : Form
    {
        string strConnection = ConfigurationManager.ConnectionStrings
        ["Test3.Properties.Settings.Test3ConnectionString"].ConnectionString;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {


            //Create connection string to Excel work book
            string excelConnectionString =
            @"Provider=Microsoft.Jet.OLEDB.4.0;
            Data Source=C:\Test.xls;
            Extended Properties=""Excel 8.0;HDR=YES;""";

            //Create Connection to Excel work book
            OleDbConnection excelConnection = new OleDbConnection(excelConnectionString);

            //Create OleDbCommand to fetch data from Excel
            OleDbCommand cmd = new OleDbCommand
            ("Select [Failure_ID], [Failure_Name], [Failure_Date], [File_Name], [Report_Name], [Report_Description], [Error] from [Failures$]", excelConnection);

            excelConnection.Open();
            OleDbDataReader dReader;
            dReader = cmd.ExecuteReader();

            SqlBulkCopy sqlBulk = new SqlBulkCopy(strConnection);
            sqlBulk.DestinationTableName = "Failures";
            sqlBulk.WriteToServer(dReader);

        }

【问题讨论】:

    标签: c# sql excel import


    【解决方案1】:

    您可以尝试 ETL(提取-转换-加载)架构:

    Extract:一个类将打开文件并获取您知道如何使用的块中的所有数据(通常您从文件中取出一行并将其数据解析为包含保存相关数据的字段的 POCO 对象),并将它们放入其他工作流程可以从中获取的队列中。在这种情况下,您可能要做的第一件事就是让 Excel 打开文件并将其重新保存为 CSV,这样您就可以在流程中将其作为基本文本重新打开并有效地进行拆分。您还可以读取列名并构建“映射字典”;此列的名称为 that,因此它转到数据对象的此属性。这个过程应该尽可能快地发生,它应该失败的唯一原因是因为行的格式与给定文件结构的您正在寻找的内容不匹配。

    转换:将文件的内容提取到基本行的实例后,执行任何验证、计算或其他必要的业务规则,将文件中的行转换为符合您的域模型的一组域对象。这个过程可以根据您的需要变得复杂,但在遵守您的需求中给出的所有业务规则的同时,它应该尽可能简单。

    加载:现在您已经在自己的域对象中获得了一个对象图,您可以使用您调用的相同持久性框架来处理以任何其他方式创建的域对象。这可以是基本的 ADO、像 NHibernate 或 MSEF 这样的 ORM,或者是对象知道如何自我持久化的 Active Record 模式。这不是批量加载,但它使您不必为了将基于文件的数据导入数据库而实现完全不同的持久性模型。

    ETL 工作流程可以帮助您将重复性任务分成简单的工作单元,然后您可以从中识别需要大量时间的任务并考虑并行流程。

    或者,您可以通过检测要使用的列并将它们排列成与您的批量输入规范相匹配的格式来获取文件并调整其格式,然后调用批量插入例程来处理数据。这个文件处理器例程可以做任何你想做的事情,包括将数据分成几个文件。但是,它是一次处理整个文件的一个大过程,优化或并行处理的机会有限。但是,如果您的加载机制很慢,或者您有大量易于消化的数据,那么它最终可能会比设计良好的 ETL 更快。

    无论如何,我会尽快摆脱 Office 格式并转为纯文本(或 XML)格式,并且我肯定会避免在服务器上安装 Office。如果有任何方法可以要求文件在加载之前采用某种易于解析的格式,例如 CSV,那就更好了。在服务器上安装 Office 通常是一件非常糟糕的事情,服务器应用程序中的 OLE 操作也好不了多少。该应用程序将非常脆弱,Office 想要告诉您的任何内容都会导致该应用程序挂起,直到您登录服务器并清除对话框。

    【讨论】:

    • @KeithS:我正在考虑将这种方法用于在一张表中有多个表格的 Excel。你有什么建议吗?
    【解决方案2】:

    如果您正在寻找更多与代码相关的答案,您可以使用以下代码来修改您的代码以处理困难的列名/不同的表:

        private void button1_Click(object sender, EventArgs e)
        {
            //Create connection string to Excel work book
            string excelConnectionString =
            @"Provider=Microsoft.Jet.OLEDB.4.0;
            Data Source=C:\Test.xls;
            Extended Properties=""Excel 8.0;HDR=YES;""";
    
            //Create Connection to Excel work book
            OleDbConnection excelConnection = new OleDbConnection(excelConnectionString);
    
            //Create OleDbCommand to fetch data from Excel
            OleDbCommand cmd = new OleDbCommand
            ("Select [Failure_ID], [Failure_Name], [Failure_Date], [File_Name], [Report_Name], [Report_Description], [Error] from [Failures$]", excelConnection);
    
            excelConnection.Open();
    
            DataTable dataTable = new DataTable();
            dataTable.Columns.Add("Id", typeof(System.Int32));
            dataTable.Columns.Add("Name", typeof(System.String));
            // TODO: Complete other table columns
            using(OleDbDataReader dReader = cmd.ExecuteReader())
            {
                DataRow dataRow = dataTable.NewRow();
                dataRow["Id"] = dReader.GetInt32(0);
                dataRow["Name"] = dReader.GetString(1);
                // TODO: Complete other table columns
                dataTable.Rows.Add(dataRow);
            }
    
            SqlBulkCopy sqlBulk = new SqlBulkCopy(strConnection);
            sqlBulk.DestinationTableName = "Failures";
            sqlBulk.WriteToServer(dataTable);
        }
    

    现在您可以控制列的名称以及将数据导入到哪些表中。 SqlBulkCopy 适用于插入大量数据。如果您只有少量的行,您最好创建一个标准的数据访问层来插入您的记录。

    【讨论】:

      【解决方案3】:

      如果您只对文本感兴趣(而不是格式等),或者您可以将 excel 文件保存为 CSV 文件,然后解析 CSV 文件,这很简单。

      【讨论】:

        【解决方案4】:

        根据程序的生命周期,我会推荐两个选项之一。

          1234563根据需要。
        1. 如果该程序将持续更长时间和/或在日常基础上找到更多用途,我建议实施类似于@KeithS 推荐的解决方案。通过一组定义明确的数据处理步骤,可以获得很大的灵活性。更具体地说,.NET Entity Framework 可能非常适合。 作为奖励,如果您尚未精通该领域,您可能会发现在第一次使用诸如 EF 之类的 ORM 期间,您学到了很多关于在边界(xls -> sql -> 等)之间处理数据的知识.

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-11-19
          • 1970-01-01
          • 1970-01-01
          • 2019-06-16
          • 1970-01-01
          • 2013-07-22
          • 1970-01-01
          相关资源
          最近更新 更多