You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#.NET SQL Server WinForm如何导出全量查询结果为PDF表格

问题说明

在.NET C# 搭配 SQL Server 开发Windows桌面应用实现PDF导出功能时,初始编写的按钮点击代码运行后仅能导出SQL查询结果的第一行数据,仅输出单条记录的日期、总收入、总支出值,无法获取全部返回行。预期效果为生成带标准表格的PDF,表头包含date、Income、Expenses三列,逐行展示所有日期对应的收入、支出汇总数据。

初始实现代码如下:

private void button1_Click(object sender, EventArgs e)
{
    Document doc = new Document();
    PdfWriter.GetInstance(doc, new FileStream("myPdf.pdf",FileMode.Create));
    doc.Open();
    SqlConnection con = new SqlConnection(connectionString);
    if (con.State == ConnectionState.Closed)
    {
        con.Open();
    }

    SqlCommand cmd = new SqlCommand("SELECT b.date,a.TotalIncome,b.TotalExpense FROM (SELECT c.date, sum(c.amout) as TotalIncome FROM (SELECT name FROM category_tbl where type = 'Income') a, transactions c where c.type = a.name group by c.date) a, (SELECT c.date, sum(c.amout) as TotalExpense FROM (SELECT name FROM category_tbl where type = 'Expense') a, transactions c where c.type = a.name group by c.date) b", con);
    SqlDataReader dr = cmd.ExecuteReader();

    if (dr.Read())
    {
        Paragraph p1 = new Paragraph(dr.GetValue(0).ToString());
        Paragraph p2 = new Paragraph(dr.GetValue(1).ToString());
        Paragraph p3 = new Paragraph(dr.GetValue(2).ToString());
        doc.Add(p1);
        doc.Add(p2);
        doc.Add(p3);
        doc.Close();
        MessageBox.Show("PDF create");
    }
}
问题根因
  • 代码使用if (dr.Read())做单次读取判断,仅会加载SqlDataReader返回的第一行数据,没有遍历全部结果集
  • 原代码直接用段落拼接文本,没有使用PDF库的表格组件构建结构化表格
  • 原SQL语句两个日期汇总子查询缺少关联条件,会产生笛卡尔积导致数据错误;同时doc.Close()写在单次读取的判断块内,即使遍历后续行也无法写入文档
  • 数据库连接、文件流等非托管资源没有做释放处理,容易引发文件占用、内存泄漏问题
修改后完整实现

代码基于当前使用的iText 5(iTextSharp)编写,其他版本PDF库API存在差异

private void button1_Click(object sender, EventArgs e)
{
    // 用using包裹所有实现IDisposable的对象,自动释放资源
    using (Document doc = new Document())
    {
        PdfWriter.GetInstance(doc, new FileStream("myPdf.pdf", FileMode.Create));
        doc.Open();

        // 创建3列的PDF表格
        PdfPTable table = new PdfPTable(3);
        // 设置表格宽度占页面宽度100%
        table.WidthPercentage = 100f;

        // 添加表头,设置字体加粗
        Font headFont = FontFactory.GetFont(FontFactory.HELVETICA_BOLD, 12);
        table.AddCell(new PdfPCell(new Paragraph("date", headFont)));
        table.AddCell(new PdfPCell(new Paragraph("Income", headFont)));
        table.AddCell(new PdfPCell(new Paragraph("Expenses", headFont)));

        using (SqlConnection con = new SqlConnection(connectionString))
        {
            con.Open();
            // 修正原SQL:添加两表日期关联条件,用全连接避免单日只有收入/支出时数据丢失,空值补0
            string sql = @"SELECT 
                                ISNULL(a.date, b.date) as date,
                                ISNULL(a.TotalIncome,0) as TotalIncome,
                                ISNULL(b.TotalExpense,0) as TotalExpense
                            FROM 
                                (SELECT c.date, sum(c.amout) as TotalIncome 
                                 FROM category_tbl a 
                                 JOIN transactions c ON c.type = a.name 
                                 WHERE a.type = 'Income'
                                 GROUP BY c.date) a
                            FULL JOIN 
                                (SELECT c.date, sum(c.amout) as TotalExpense 
                                 FROM category_tbl a 
                                 JOIN transactions c ON c.type = a.name 
                                 WHERE a.type = 'Expense'
                                 GROUP BY c.date) b
                            ON a.date = b.date
                            ORDER BY ISNULL(a.date, b.date)";

            SqlCommand cmd = new SqlCommand(sql, con);
            using (SqlDataReader dr = cmd.ExecuteReader())
            {
                // 循环读取所有行,替换原来的if单次判断
                while (dr.Read())
                {
                    // 逐行把数据加入表格单元格
                    table.AddCell(dr["date"].ToString());
                    table.AddCell(dr["TotalIncome"].ToString());
                    table.AddCell(dr["TotalExpense"].ToString());
                }
            }
        }

        // 把整个表格加入PDF文档
        doc.Add(table);
        // 文档关闭操作移到循环外,确保所有内容写入完成后再关闭
        doc.Close();
        MessageBox.Show("PDF create");
    }
}
关键改动说明
  • 把单次if (dr.Read())替换为while (dr.Read())循环,遍历查询返回的所有结果行
  • 引入PdfPTable组件创建3列表格,单独添加加粗表头,所有数据逐行写入表格单元格,最终统一将表格加入PDF文档
  • 修正原SQL的语法缺陷:添加两个子查询的日期关联条件避免笛卡尔积,用全连接+ISNULL处理单日无收入/无支出的场景,空值补0避免显示异常,增加日期排序保证输出顺序符合预期
  • 所有数据库连接、数据流、PDF文档对象都用using语句包裹,离开作用域后自动释放资源,无需手动判断连接状态、手动释放对象
  • 将文档关闭、弹窗提示逻辑移到资源块内,确保所有数据写入完成后再关闭文档,不会出现内容截断问题

内容的提问来源于stack exchange,提问作者Lochana Liyange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 03:03:39