在ASP.Net中将大数据表复制到excel中

时间:2016-02-21 21:52:00

标签: c# asp.net sql-server excel

我已经编写了一些代码,可以将Azure数据库中的数据复制到Excel文件中。这可以在这个问题的最后找到。

问题是当我有一个表的10k行时,填充excel表需要永远。显然,这对于Excel来说并不理想,但在这一点上它必须以这种方式完成。我想知道是否有更快的方法对此进行编码。 当然,创建Excel工作表是瓶颈,因为C#会在几秒钟内抓取数据集。如果我进入Excel并查看数据,然后右键单击并使用标题进行复制并将其粘贴到Excel表格中,它也会在几秒钟内完成。

enter image description here

我可以通过编程方式执行此操作吗?

private void createExcelFile()
        {
            string fileName = "FvGReport.xlsx";
            string filePath = HttpContext.Current.Request.MapPath("~/App_Data/" + fileName); //check www.dotnetperls.com/mappath
            string sqlQuery = "";
            List<string> sheetNames = new List<string>();

            foreach (ListItem item in ddlSummary_Supplier.Items)
            {
                string sqlSummary = "SELECT * FROM FvGSummaryAll WHERE Supplier_Code = '" + item.Text + "'; ";
                sqlQuery = sqlQuery + sqlSummary;
                sheetNames.Add("Summary " + item.Text);

                string sqlPaymentsSummary = "SELECT * FROM FvGSummaryPayment WHERE Supplier_Code = '" + item.Text + "'; ";
                sqlQuery = sqlQuery + sqlPaymentsSummary;
                sheetNames.Add("PaymentSummary " + item.Text);
            }

            DataSet dataSet = new DataSet();
            //string sqlQuery = @"SELECT * FROM FvGData WHERE Supplier_Code = 'SFF Pacific'; SELECT * FROM FvGSummaryPayment";


            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                connection.Open();
                SqlDataAdapter adapter = new SqlDataAdapter();
                adapter.SelectCommand = new SqlCommand(sqlQuery, connection);
                adapter.Fill(dataSet);
            }

            //this reference conflicts with System.Data as both have DataTable. So defining it here. 
            Microsoft.Office.Interop.Excel.Application ExcelApp = new Microsoft.Office.Interop.Excel.Application();
            Microsoft.Office.Interop.Excel.Workbook excelWorkBook = null;
            Microsoft.Office.Interop.Excel.Worksheet excelWorkSheet = null;
            ExcelApp.Visible = true;
            excelWorkBook = ExcelApp.Workbooks.Add(Microsoft.Office.Interop.Excel.XlWBATemplate.xlWBATWorksheet);


            //excel rows start at 1 not 0
            try
            {
                for (int i = 1; i < dataSet.Tables.Count; i++)
                {
                    excelWorkBook.Worksheets.Add();  //Adds new sheet in Excel WorkBook
                }

                for (int i = 0; i < dataSet.Tables.Count; i++)
                {
                    int dsRow = 1;
                    excelWorkSheet = excelWorkBook.Worksheets[i + 1];

                    //Writing Columns Name in Excel Sheet
                    for (int col = 1; col < dataSet.Tables[i].Columns.Count; col++)
                    {
                        excelWorkSheet.Cells[dsRow, col] = dataSet.Tables[i].Columns[col - 1].ColumnName;
                    }
                    dsRow++;

                    for (int xlRow = 0; xlRow < dataSet.Tables[i].Rows.Count; xlRow++)
                    {
                        //Excel row and col positions for writing row = 1, col = 1
                        for (int col = 1; col < dataSet.Tables[i].Columns.Count; col++)
                        {
                            excelWorkSheet.Cells[dsRow, col] = dataSet.Tables[i].Rows[xlRow][col - 1].ToString();                           
                        }
                        dsRow++;
                    }

                    excelWorkSheet.Name = sheetNames[i]; //Renaming ExcelSheets
                }

                excelWorkBook.SaveAs(filePath);
                excelWorkBook.Close();
                ExcelApp.Quit();
                Marshal.ReleaseComObject(excelWorkSheet);
                Marshal.ReleaseComObject(excelWorkBook);
                Marshal.ReleaseComObject(ExcelApp);
            }
            catch (Exception ex)
            {
                lblNoData.Text = ex.ToString();
            }
            finally
            {
                foreach (Process process in Process.GetProcessesByName("Excel"))
                {
                    process.Kill();
                }
            }

            downloadExcel(filePath, fileName);
        }

3 个答案:

答案 0 :(得分:0)

根据我的经验,看起来你正在使用Office Automation,这在这类事情上通常很慢。我建议将输出保存为分隔文件(.csv)并使用自动化用Excel打开该文件(或文件),然后将其另存为电子表格。

答案 1 :(得分:0)

我建议你尝试使用一些ETL工具,特别是如果你不时再这样做的话。例如,如果您使用Talend,那么您将连接到数据库,并且架构将自行提取。获取SQL输入组件并将其连接到Excel组件,您就完成了。大约需要5分钟,没有一行代码

答案 2 :(得分:0)

我不确定你的意思永远&#39;但是为了比较我有一个过程,写一个46,124行的OpenXML电子表格,每行约500个字符,不到17秒。这是由C#进程生成的,该进程位于与数据库服务器相同的托管设施的单独服务器上。

如果可以选择写入CSV,那么这将是性能最佳的解决方案。 OpenXML将为您提供下一个最佳性能,我发现以下文章在我尝试整理过程时最有帮助:

Read-and-Write-Microsoft-Excel-with-Open-XML-SDK

关于内存 - 您需要将两件事放入内存,传入数据和传出文件。无论您撰写的文件类型是什么,您都希望使用SqlDataReader代替dataSet。这意味着您的传入数据在内存中一次只能有一行(而不是全部10K)。在编写文件(CSV或OpenXML)时,如果直接写入磁盘(FileStream)而不是内存(MemoryStream),那么你只需要在内存中占用一点点。

特别是如果您运行的是在您的网站中运行的代码,您不希望一次性使用大量内存,因为.NET / IIS无法很好地处理这些内存。