【问题标题】:C# read excel data using oledb and format it in specified format and insert into SQL Server databaseC#使用oledb读取excel数据并将其格式化为指定格式并插入SQL Server数据库
【发布时间】:2016-05-13 08:32:18
【问题描述】:

net 和 C#。我需要编写一个程序来浏览和读取一个excel,然后以指定的格式解析它,最后插入到sql server数据库中。

  1. 我使用 oledb 读取 excel,并从 excel 创建了 DataTable。现在我无法以所需的格式解析它。这是关于什么是 excel 输入以及插入数据库的预期格式的图片的链接。 Input and expected output format

  2. 现在我正在处理简单的数据,将来我需要处理大约 3000 列的大型 Excel 数据,以解析成大约 250000 条记录。还请在性能方面给我建议。现在我正在使用 oledb 是不是很好还是我需要使用其他任何东西。

这是我的示例代码 c# 代码文件

    OleDbConnection Econ;
    SqlConnection con;

    string constr, Query, sqlconn;
    protected void Page_Load(object sender, EventArgs e)
    {


    }

    // excel connection
    private void ExcelConn(string FilePath)
    {

        constr = string.Format(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0};Extended Properties=""Excel 12.0 Xml;HDR=YES;""", FilePath);
        Econ = new OleDbConnection(constr);

    }

    // sql connection
    private void connection()
    {
        sqlconn = ConfigurationManager.ConnectionStrings["SqlCom"].ConnectionString;
        con = new SqlConnection(sqlconn);

    }

    // read data from excel and creating a datatable
    private void ExcelToDataTable(string FilePath)
    {
        ExcelConn("C:\\Users\\username\\Desktop\\EmpEx.xlsx");

        Query = string.Format("Select * FROM [Sheet1$]");
        OleDbCommand Ecom = new OleDbCommand(Query, Econ);
        Econ.Open();

        OleDbDataAdapter oda = new OleDbDataAdapter(Ecom);
        DataTable dtExcel = new DataTable();
        Econ.Close();
        oda.Fill(dtExcel);

       // DataTable parseTable = ParseDataTable(dtExcel);

        //connection();


        // printing data table
        foreach (DataRow dataRow in dtExcel.Rows)
        {
            foreach (var item in dataRow.ItemArray)
            {
                Response.Write(item);
            }
        }

        Response.Write("<br> Colums: " + dtExcel.Columns.Count.ToString() + "<br>");
        Response.Write("Rows: " + dtExcel.Rows.Count.ToString() + "<br>");
        //print on screen
        foreach(DataRow row in dtExcel.Rows)
        {

            foreach(DataColumn col in dtExcel.Columns)
            {
                Label1.Text = Label1.Text  + row[col].ToString() + "\t";

            }


        }
    }

    // Method to make data table in specified format
    public DataTable ParseDataTable(DataTable dtExcel)
    {
        var dt = new DataTable("sourceData");
        dt.Columns.Add(new DataColumn("id", typeof(String)));
        dt.Columns.Add(new DataColumn("name", typeof(String)));
        dt.Columns.Add(new DataColumn("variable", typeof(String)));
        dt.Columns.Add(new DataColumn("year", typeof(String)));
        dt.Columns.Add(new DataColumn("value", typeof(String)));

        // NOT GETTING TO PARSE In specified format
        /**** NEED HELP HERE *****/

        return dt;
    }


    protected void Button1_Click(object sender, EventArgs e)
    {
        string CurrentFilePath = Path.GetFullPath(FileUpload1.PostedFile.FileName);
        ExcelToDataTable(CurrentFilePath);
    }  

请帮助我如何实现这一目标。如链接(屏幕截图)中的附图中所述,如何解析指定格式的输入 excel 数据。请建议我解决我的问题的任何方法。

【问题讨论】:

    标签: c# asp.net excel ado.net oledb


    【解决方案1】:

    我使用 C# OLEDB ACE 引擎解决了这个问题。目前它只支持大约 250 列。到目前为止,它满足了我的要求。

    解决方案是我能够通过输入文件的代码获取工作表名称和工作表范围。我将输入文件复制到 C# oledb 数据表 inputtable 中,使用该数据表创建了另一个格式化的数据表,该数据表根据条件逻辑保存来自 inputtable 的值。我使用 linq 查询数据表以生成格式化结果。

    点击按钮:

           string rangeStringwithSHeet = sheetName + excelComm.GetRange(sheetName, excelConn);
    
            dataQuery = string.Format("SELECT Institution" + queryIn + "  FROM [{0}] ", rangeStringwithSHeet);
    
            // connect to excel with query and get the initiall datatable from excel input
            dataExcelTable = excelComm.FillDataTableWithQuery(dataQuery, excelConn);
             formattedDataTableExcel(dataExcelTable);
    

    我在 formattedDataTableExcel() 方法中包含的实际转换逻辑,我在其中为我的 Web 应用程序创建了它。我根据我的业务逻辑编写逻辑。 我没有在这里发布实际的逻辑。如果有人遇到类似问题,请告诉我,我可以帮助您完成转换过程。

    【讨论】:

      【解决方案2】:

      我的建议是重新考虑您的工具。这在像 SQL Server Integration Services (SSIS) 这样的工具或其他仅用于此目的的工具中会容易得多。

      来自SSIS Wiki article,“SSIS 是一个用于数据集成和工作流应用程序的平台。”

      来自C# Wiki article“C#(发音为 see sharp)是一种多范式编程语言”。

      【讨论】:

      • 我为此尝试了 Talend 开源 ETL 工具(数据集成)。当我的输入 Excel 表中有超过 1000 列时,该工具未检测到我的 Excel 输入。我在网上搜索了使用 SSIS 进行格式化,但没有找到任何符合我要求的内容。如果您能向我推荐任何网址或示例,我将不胜感激。谢谢。
      【解决方案3】:

      我已经创建了一个解决方案,用于在 F# 中取消透视数据,可以在 here 中找到它。由于 F# 适用于 .NET CLR,因此您可以从 C# 调用它,也可以使用 linq 等效操作将其转换为 C#。

      // Sample Input as a jagged array
      let sampleInput =
          [| [| "id"; "name"; "variable1"; "variable1"; "variable2" |]
             [| ""; ""; "Fall 2000"; "Fall 2001"; "Fall 2000" |]
             [| "1"; "abc"; "1400"; "1500"; "1200" |]
             [| "2"; "xyz"; "1200"; "1400"; "1100" |] |]
      
      let variables = sampleInput.[0].[2 ..]
      let falls = sampleInput.[1].[2 ..]
      let idNameValues = sampleInput.[2 ..] |> Array.map (fun value -> (value.[0], value.[1], value.[2 ..]))
      
      // Output as an array of tuples
      let output =
          idNameValues
          |> Array.collect (fun (id, name, values) -> 
              Array.zip3 variables falls values // Zip up the variables, falls and values data arrays for each old id, name combination
              |> Array.mapi (fun i (variable, fall, value) -> (i, int id, name, variable, fall, value)) // Flatten out over the row id, old id index and name
          )
          |> Array.sortBy (fun (row, id, _, _, _, _) -> (row, id)) // Sort by row id and old id index
          |> Array.mapi (fun i (_, _, name, variable, fall, value) -> (i + 1, name, variable, fall, int value)) // Add new id index
      
      printfn "SampleInput =\n %A" sampleInput                 
      printfn "Output =\n %A" output
      

      我实际上已经尝试将 F# 代码转换为 C#。我相信您可能可以在这里编写更多惯用的 C# 代码,并且由于大量的 linq,性能可能也有所欠缺,但它似乎可以工作!

      你可以看到它在 .NET Fiddle here 中工作。

      using System;
      using System.Linq;
      
      public class Program
      {   
          public static string[][] SampleInput()
          {
              return new string[][]{ 
                  new string[] { "id", "name", "variable1", "variable1", "variable2" },
                  new string[] { "", "", "Fall 2000", "Fall 2001", "Fall 2000" },
                  new string[] { "1", "abc", "1400", "1500", "1200" },
                  new string[] { "2", "xyz", "1200", "1400", "1100" } 
              };
          }
      
          public static Tuple<int, string, string, string, int>[] Unpivot(string[][] flattenedInput)
          {
              var variables = (flattenedInput[0]).Skip(2).ToArray();
              var falls = (flattenedInput[1]).Skip(2).ToArray();
              var idNameValues = flattenedInput.Skip(2).Select(idNameValue => Tuple.Create(idNameValue[0], idNameValue[1], idNameValue.Skip(2))).ToArray();
      
              return
                  idNameValues
                      .SelectMany(idNameValue => variables
                          .Zip(falls, (variable, fall) => Tuple.Create(variable, fall))
                          .Zip(idNameValue.Item3, (variableFall, val) => Tuple.Create(variableFall.Item1, variableFall.Item2, val))
                          .Select((variableFallVal, i) => Tuple.Create(i + 1, Convert.ToInt32(idNameValue.Item1), idNameValue.Item2, variableFallVal.Item1, variableFallVal.Item2, variableFallVal.Item3))
                      )
                      .OrderBy(rowId_ => Tuple.Create(rowId_.Item1, rowId_.Item2))
                      .Select((_NameVariableFallValue, i) => Tuple.Create(i + 1, _NameVariableFallValue.Item3, _NameVariableFallValue.Item4, _NameVariableFallValue.Item5, Convert.ToInt32(_NameVariableFallValue.Item6)))
                      .ToArray();
          }
      
          public static void Main()
          {
              var flattenedData = SampleInput();
              var normalisedData = Unpivot(SampleInput());
      
              Console.WriteLine("SampleInput =");
              foreach (var row in SampleInput())
              {
                  Console.WriteLine(Tuple.Create(row[0], row[1], row[2], row[3], row[4]).ToString());
              }       
      
              Console.WriteLine("\nOutput =");
              foreach (var row in normalisedData)
              {
                  Console.WriteLine(row.ToString());
              }
          }
      }
      

      编辑: 下面是一个将文件路径表示的 excel 文件转换为锯齿状字符串数组的示例。在这种情况下,我使用 Nuget Package ExcelDataReader 从 Excel 中获取数据。

      using System;
      using System.IO;
      using System.Data;
      using System.Collections.Generic;
      using System.Linq;
      using Excel;  // Install Nuget Package ExcelDataReader
      
      public class Program
      {
          public static string[][] ExcelSheetToJaggedArray(string fileName, string sheetName)
          {
              using (var stream = File.Open(fileName, FileMode.Open, FileAccess.Read))
              {
                  using (var excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream))
                  {
                      var data =
                          excelReader.AsDataSet().Tables
                              .Cast<DataTable>()
                              .FirstOrDefault(sheet => sheet.TableName == sheetName);
      
                      return
                          data.Rows
                              .Cast<DataRow>()
                              .Select(row => 
                                  row.ItemArray 
                                      .Select(cell => cell.ToString()).ToArray())
                              .ToArray();
                  }
              }
          }
      
          public static void Main()
          {
              // Sample use of ExcelSheetToJaggedArray function
              var fileName = @"C:\SampleInput.xlsx";
              var jaggedArray = ExcelSheetToJaggedArray(fileName, "Sheet1");
      
              foreach (var row in jaggedArray)
              {
                  foreach (var cell in row)
                  {
                      Console.Write(cell.ToString() + ",");
                  }
                  Console.WriteLine();
              }
          }
      }
      

      【讨论】:

      • 谢谢。但在这里我必须从 excel 中读取数据,而不是从数组中读取数据。在 F# 中是否有可能。我是 C# 和 Asp.net 的新手,F# 的代码对我来说看起来很新。尽管我非常感谢您最初的快速回复。
      • @priya777 是的,我试图专注于将扁平数据转换为规范化数据的步骤。例如,我认为将 Excel 转换为等价的锯齿数组对您来说不会太难。与其尝试在一个步骤/方法中完成所有事情,不如将逻辑分解为 2 个或 3 个。即 Excel -> Excel 数据表 -> 扁平化的锯齿状数组 -> 标准化数组 -> sql server
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-08
      • 1970-01-01
      • 2021-11-23
      • 2015-12-05
      • 1970-01-01
      相关资源
      最近更新 更多