从多选ListBox构建SQL IN语句查询无结果且无报错问题排查
问题分析与解决方案
先帮你拆解下代码里的问题,以及可能导致无数据返回的原因:
1. 冗余的变量定义
你连续写了两次StringBuilder sb = new StringBuilder("SELECT ... WHERE ");,这会直接覆盖第一个实例的内容,虽然这次逻辑上没影响结果,但属于无效冗余代码,建议删掉重复的那行。
2. 直接拼接SQL字符串的隐患
你直接把ListBox选中项的文本用单引号包裹后拼进IN语句,这里有两个核心问题:
- SQL注入风险:如果员工姓名里包含单引号(比如
O'Conner),会直接导致SQL语法错误;就算当前没遇到这种情况,这也是严重的安全漏洞。 - 匹配精度问题:如果ListBox的
Text和数据库中Emp_Name的内容存在大小写差异、首尾空格(比如ListBox显示张三,数据库里是张三),会直接导致匹配失败,查不到数据。
3. 边界情况未处理
如果ListBox没有选中任何项,InPartQuery会是空字符串,最终SQL会变成WHERE Emp_Attend.Emp_Name IN (),这是非法的SQL语法——虽然你说没有报错,但可能你的场景里默认有选中项,但这个逻辑漏洞必须修复。
修正后的参数化查询代码
我给你改成参数化查询的写法,既解决上述问题,又能保证安全和稳定性:
// 修复重复定义问题,用多行字符串让SQL更易读 StringBuilder sb = new StringBuilder(@" SELECT * FROM Emp_Attend LEFT JOIN Employees ON Emp_Attend.Emp_ID = Employees.EmpID WHERE 1=1 "); // 用1=1简化后续条件拼接逻辑 using (SqlCommand cmdSQL = new SqlCommand()) { // 提取选中的项文本 var selectedNames = ListBox1.Items .Cast<ListItem>() .Where(t => t.Selected) .Select(r => r.Text) .ToList(); if (selectedNames.Any()) { // 构建参数化的IN语句 var parameters = new List<SqlParameter>(); sb.Append("AND Emp_Attend.Emp_Name IN ("); for (int i = 0; i < selectedNames.Count; i++) { var paramName = $"@EmpName{i}"; sb.Append(i == 0 ? paramName : $", {paramName}"); parameters.Add(new SqlParameter(paramName, selectedNames[i])); } sb.Append(")"); } // 没有选中项时,可以根据需求调整:比如返回所有数据,或者加提示 cmdSQL.CommandText = sb.ToString(); cmdSQL.Connection = sqlcon; cmdSQL.Parameters.AddRange(parameters.ToArray()); SqlDataAdapter da = new SqlDataAdapter(cmdSQL); DataTable dtbl = new DataTable(); da.Fill(dtbl); // 不需要手动关闭连接:da.Fill会自动处理连接状态(关闭时打开,执行后关闭;已打开则保持打开) // sqlcon.Close(); gvEmployees.DataSource = dtbl; gvEmployees.DataBind(); }
额外排查点(如果调整后仍无数据)
- 把生成的SQL语句复制到SQL Server Management Studio中执行,确认数据库本身是否存在符合条件的数据。
- 检查ListBox的
Text与数据库Emp_Attend.Emp_Name的实际值是否完全一致(包括大小写、空格),可以考虑用LTRIM(RTRIM(Emp_Attend.Emp_Name))去除空格后匹配,或者在ListBox绑定阶段就统一文本格式。 - 确认关联条件
Emp_Attend.Emp_ID = Employees.EmpID是否正确,有没有因为关联错误导致数据被过滤。
内容的提问来源于stack exchange,提问作者Youssef Hany
相关产品推荐
相关产品推荐

