使用Excel Interop类从SQL数据库生成Excel文件问题求助
解决Excel Interop无法从DataSet写入数据到Excel的问题
我看了你的代码,马上发现了核心问题——你创建了SqlDataAdapter但没有把查询结果填充到DataSet里,导致ds是空的,遍历ds.Tables的循环根本不会执行,自然没有数据写入Excel。下面是修复后的完整代码,顺便帮你优化了几个潜在问题:
private void linkLabel10_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) { using (var fbd = new FolderBrowserDialog()) { DialogResult result = fbd.ShowDialog(); if (result == DialogResult.OK && !string.IsNullOrWhiteSpace(fbd.SelectedPath)) { // 简化文件名拼接,避免索引越界风险 string comboBox1Text = comboBox1.Text.Substring(0, comboBox1.Text.IndexOf("*") - 1); string comboBox2Part1 = comboBox2.Text.Substring(0, comboBox2.Text.IndexOf("(") - 1); string comboBox2Part2 = comboBox2.Text.Substring(comboBox2.Text.IndexOf("(") + 1, 10); string fileTest = Path.Combine(fbd.SelectedPath, $"{comboBox1Text}-{comboBox2Part1}-{comboBox2Part2}.xlsx"); MessageBox.Show(fileTest); if (File.Exists(fileTest)) { File.Delete(fileTest); } // 使用参数化查询避免SQL注入风险! string sqlQuery = @"select PersonelKodu= ztSinifEgitimiDurum.KisiID, İsim= dbo.cdCurrAcc.FullName, Katılım = CASE WHEN Katilim = 1 THEN 'Katıldı' ELSE 'Katılmadı' END, ztSinifEgitimiDurum.ID FROM dbo.ztSinifEgitimiDurum INNER JOIN dbo.cdCurrAcc ON cdCurrAcc.CurrAccCode = ztSinifEgitimiDurum.KisiID AND cdCurrAcc.CurrAccTypeCode = ztSinifEgitimiDurum.KisiTipiID WHERE AtamaID = @AtamaID"; SqlDataAdapter da = new SqlDataAdapter(sqlQuery, baglan); da.SelectCommand.Parameters.AddWithValue("@AtamaID", AtamaIDBul()); // 参数化传递ID DataSet ds = new DataSet(); da.Fill(ds); // 关键!把查询结果填充到DataSet中 Excel.Application excelApp = null; Excel.Workbook excelWorkBook = null; Excel.Worksheet excelWorkSheet = null; try { excelApp = new Excel.Application(); excelWorkBook = excelApp.Workbooks.Add(); excelWorkSheet = (Excel.Worksheet)excelWorkBook.Worksheets.Item[1]; excelWorkSheet.Name = "Ali"; // 写入表头 if (ds.Tables.Count > 0) { DataTable table = ds.Tables[0]; for (int i = 1; i <= table.Columns.Count; i++) { excelWorkSheet.Cells[1, i] = table.Columns[i - 1].ColumnName; // MessageBox.Show(table.Columns[i - 1].ColumnName.ToString()); } // 写入数据行 for (int j = 0; j < table.Rows.Count; j++) { for (int k = 0; k < table.Columns.Count; k++) { excelWorkSheet.Cells[j + 2, k + 1] = table.Rows[j].ItemArray[k].ToString(); } } } excelWorkBook.SaveAs(fileTest); MessageBox.Show("Excel文件生成成功!"); } catch (Exception ex) { MessageBox.Show($"生成Excel时出错:{ex.Message}"); } finally { // 正确释放COM资源,避免Excel进程残留 if (excelWorkBook != null) { excelWorkBook.Close(); Marshal.ReleaseComObject(excelWorkBook); } if (excelApp != null) { excelApp.Quit(); Marshal.ReleaseComObject(excelApp); } if (excelWorkSheet != null) { Marshal.ReleaseComObject(excelWorkSheet); } } } } }
关键修复和优化点:
- 填充DataSet:添加了
da.Fill(ds),这是把SQL查询结果加载到DataSet的核心步骤,没有这一步你的DataSet是空的 - 参数化查询:把原来的字符串拼接SQL改成参数化查询,彻底避免SQL注入风险,这是数据库操作的最佳实践
- 资源释放:使用
finally块手动释放Excel的COM对象,防止后台残留Excel进程(这是Excel Interop常见的坑) - 异常处理:添加了
try-catch块,能捕获并提示生成过程中的错误,方便调试 - 文件名拼接优化:用
Path.Combine拼接路径,避免手动拼接字符串时的路径分隔符问题,同时拆分了字符串截取逻辑,提高可读性
额外提示:
如果你的数据量较大,Excel Interop的性能会比较差,建议考虑使用EPPlus、NPOI等开源库来生成Excel,它们不需要安装Excel,性能也更好。
内容的提问来源于stack exchange,提问作者Yunus
相关产品推荐
相关产品推荐

