SQL Server从两张表查询登录数据 提示无第0行数据报错如何解决
错误原因分析
- SQL逻辑错误:
INNER JOIN要求两张表同时存在相同Unam的关联数据才会返回结果,完全不符合你「匹配任意一张表凭证即可通过校验」的需求。且你当前的查询仅校验了Login_User的账号密码,未对Add_User的凭证做校验,逻辑完全偏离需求。 - 空结果防护缺失:当查询没有匹配数据时,
dt.Rows是空集合,直接访问dt.Rows[0]就会抛出「There is no row at position 0」的报错。 - 结果判断逻辑错误:你使用
select *返回的是表的业务字段,第一列是Unam这类内容,根本不可能等于字符串"1",就算查询到了数据也会走校验失败的分支。 - 存在SQL注入风险:直接拼接用户输入的账号密码到SQL语句,极易被注入攻击泄露全库数据。
解决步骤
1. 修正SQL查询逻辑
用UNION ALL合并两张表的账号密码数据,不需要关联查询即可实现「匹配任意一张表凭证」的需求,同时用参数化查询避免注入风险:
SELECT COUNT(1) as LoginCount FROM ( SELECT Unam, Pswd FROM Login_User UNION ALL SELECT Unam, Pswd FROM Add_User ) t WHERE t.Unam = @username AND t.Pswd = @password
2. 修正后端C#逻辑
改用ExecuteScalar直接获取匹配计数,不需要填充DataTable,同时增加空结果防护:
string conStr = @"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Product.mdf;Integrated Security=True;User Instance=True"; string sql = @"SELECT COUNT(1) as LoginCount FROM ( SELECT Unam, Pswd FROM Login_User UNION ALL SELECT Unam, Pswd FROM Add_User ) t WHERE t.Unam = @username AND t.Pswd = @password"; using (SqlConnection con = new SqlConnection(conStr)) { con.Open(); using (SqlCommand cmd = new SqlCommand(sql, con)) { // 参数化赋值自动处理特殊字符,避免SQL注入 cmd.Parameters.AddWithValue("@username", txtUser.Text.Trim()); cmd.Parameters.AddWithValue("@password", txtPswd.Text); int loginCount = Convert.ToInt32(cmd.ExecuteScalar()); if (loginCount > 0) { // 校验通过跳转首页 this.Hide(); Home hm = new Home(); hm.ShowDialog(); } else { MessageBox.Show("Invalid User Name or Password!."); } } }
3. 额外优化建议
- 不要明文存储密码,建议用BCrypt等加密算法加盐存储,校验时先对用户输入的密码加密再和库中密文对比。
- 提前清理两张表中
Unam相同但密码不同的冲突数据,避免出现校验逻辑异常。
内容的提问来源于stack exchange,提问作者Md Mashkoor Alam
相关产品推荐
相关产品推荐

