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

如何在C#中从SQL两张表筛选未归还书籍并显示到DataGridView

获取未归还书籍并绑定到DataGridView的C#实现

嘿,这个需求其实很常见,咱们先理清楚核心逻辑:要找出用户借阅过但没归还的书,本质就是借阅表中有记录,但归还表中找不到对应归还记录的书籍。接下来我给你一步步的实现方案:

第一步:编写正确的SQL查询

咱们有两种常用且高效的写法来获取目标数据,你可以根据自己的习惯选择:

写法1:使用NOT EXISTS(推荐,性能更优)

这种写法数据库优化器更容易生成高效的执行计划,适合数据量较大的场景:

SELECT bb.BookId, bb.BookName, bb.BorrowDate
FROM [Books Burrowed] bb
WHERE bb.UserId = @UserId
AND NOT EXISTS (
    SELECT 1 
    FROM [Books Returned] br 
    WHERE br.BookId = bb.BookId 
    AND br.UserId = bb.UserId
)

写法2:使用LEFT JOIN

这种写法逻辑更直观,适合理解关联查询的场景:

SELECT bb.BookId, bb.BookName, bb.BorrowDate
FROM [Books Burrowed] bb
LEFT JOIN [Books Returned] br 
    ON bb.BookId = br.BookId 
    AND bb.UserId = br.UserId
WHERE bb.UserId = @UserId
AND br.BookId IS NULL

第二步:C#代码实现(ADO.NET示例)

假设你用的是SQL Server数据库,下面是完整的WinForm示例代码,包含数据库连接、查询、绑定到DataGridView的逻辑,还做了异常处理和安全防护:

using System.Data;
using System.Data.SqlClient;
using System.Windows.Forms;

public class BookBorrowManager
{
    // 替换成你的实际数据库连接字符串
    private readonly string _connectionString = "Data Source=你的服务器名;Initial Catalog=你的数据库名;Integrated Security=True;";

    /// <summary>
    /// 加载指定用户未归还的书籍到DataGridView
    /// </summary>
    /// <param name="userId">用户ID</param>
    /// <param name="dgv">要绑定的DataGridView控件</param>
    public void LoadUnreturnedBooks(int userId, DataGridView dgv)
    {
        // 先清空控件原有数据
        dgv.DataSource = null;

        // 使用using语句自动释放数据库连接等资源,避免内存泄漏
        using (SqlConnection conn = new SqlConnection(_connectionString))
        {
            // 这里用NOT EXISTS的SQL,你也可以换成LEFT JOIN的版本
            string sqlQuery = @"
                SELECT bb.BookId, bb.BookName, bb.BorrowDate
                FROM [Books Burrowed] bb
                WHERE bb.UserId = @UserId
                AND NOT EXISTS (
                    SELECT 1 
                    FROM [Books Returned] br 
                    WHERE br.BookId = bb.BookId 
                    AND br.UserId = bb.UserId
                )";

            using (SqlCommand cmd = new SqlCommand(sqlQuery, conn))
            {
                // 添加参数化查询,彻底避免SQL注入风险
                cmd.Parameters.AddWithValue("@UserId", userId);

                try
                {
                    conn.Open();
                    // 用SqlDataAdapter填充DataTable
                    SqlDataAdapter dataAdapter = new SqlDataAdapter(cmd);
                    DataTable unreturnedBooksTable = new DataTable();
                    dataAdapter.Fill(unreturnedBooksTable);

                    // 将DataTable绑定到DataGridView
                    dgv.DataSource = unreturnedBooksTable;

                    // 优化列显示名称,让界面更友好
                    dgv.Columns["BookId"].HeaderText = "书籍ID";
                    dgv.Columns["BookName"].HeaderText = "书籍名称";
                    dgv.Columns["BorrowDate"].HeaderText = "借阅日期";
                }
                catch (SqlException sqlEx)
                {
                    MessageBox.Show($"数据库查询出错:{sqlEx.Message}", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"发生未知错误:{ex.Message}", "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }
    }
}

// 调用示例(比如在WinForm的按钮点击事件中)
private void btnLoadUnreturnedBooks_Click(object sender, EventArgs e)
{
    // 这里假设当前用户ID是1,实际项目中可以从登录会话、用户控件等地方获取
    int currentLoginUserId = 1;
    BookBorrowManager borrowManager = new BookBorrowManager();
    borrowManager.LoadUnreturnedBooks(currentLoginUserId, dataGridView1);
}

一些关键注意事项

  • 务必替换_connectionString中的服务器名、数据库名,如果是SQL Server身份验证,要加上User ID=你的用户名;Password=你的密码;。
  • 坚持使用参数化查询,这是防止SQL注入的核心手段,绝对不能直接拼接SQL字符串。
  • 如果你的表字段名(比如书籍名称叫Title而不是BookName)或者表名有差异,要对应修改SQL查询和DataGridView的列名设置。
  • 可以根据业务需求扩展SQL查询的字段,比如加上书籍作者、分类等,只要在SELECT语句中添加对应字段即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:05:25