求助:如何按ItemNo搜索拆分存储的Stock_ID与Stock_No?
解决按合并后的ItemNo搜索库存数据的问题
看起来你遇到的核心问题是:数据库里把ItemNo拆成了Stock_No(前缀如MG)和Stock_ID(自增数字如1)存储,GridView里能合并成MG001格式展示,但搜索时没法正确匹配这个合并后的格式。你的原有搜索SQL逻辑是让Stock_No和Stock_ID同时匹配输入文本,这显然不对——比如输入MG001时,Stock_No是MG,Stock_ID是1,两者都不会匹配MG001,所以搜不到结果。
下面给你两种可行的解决方案,同时帮你修复代码里的其他问题(比如SQL注入风险):
方案1:在SQL中合并字段并匹配搜索文本
直接在查询语句里把Stock_No和补零后的Stock_ID拼接成ItemNo格式,再和搜索文本做模糊匹配。这种方法不需要拆分用户输入,逻辑更直观。
修改后的搜索代码如下(注意用参数化查询避免SQL注入,这是非常重要的!):
private void bunifuMetroTextbox1_KeyUp(object sender, KeyEventArgs e) { // 关闭之前的连接(如果有) if (conn.State == ConnectionState.Open) conn.Close(); try { conn.Open(); // 用参数化查询,避免SQL注入 string query = @"SELECT TOP 2 * FROM Stock_Entry WHERE CONCAT(Stock_No, RIGHT('000' + CAST(Stock_ID AS VARCHAR), 3)) LIKE @SearchText + '%'"; SqlCommand cmd = new SqlCommand(query, conn); // 添加参数,自动处理特殊字符 cmd.Parameters.AddWithValue("@SearchText", bunifuMetroTextbox1.Text); DataTable dt = new DataTable(); SqlDataAdapter da = new SqlDataAdapter(cmd); da.Fill(dt); // 这里注意:直接绑定DataSource后,GridView不会自动合并列,需要重新处理显示 dataGridView1.DataSource = dt; // 遍历行,重新生成ItemNo并替换第一列的值 foreach (DataGridViewRow row in dataGridView1.Rows) { if (!row.IsNewRow) { string sNo = row.Cells["Stock_No"].Value.ToString(); int sId = int.Parse(row.Cells["Stock_ID"].Value.ToString()); string itemNo = string.Format("{0}{1:D3}", sNo, sId); row.Cells[0].Value = itemNo; } } } catch (Exception ex) { // 记得捕获异常后提示用户,不要空catch MessageBox.Show($"搜索出错:{ex.Message}"); } finally { // 确保连接关闭 if (conn.State == ConnectionState.Open) conn.Close(); } }
方案2:在C#中拆分搜索文本,分别匹配字段
如果你的Stock_No都是纯字母、Stock_ID都是纯数字,也可以在代码里拆分用户输入的文本,分离字母部分和数字部分,然后分别匹配Stock_No和Stock_ID:
private void bunifuMetroTextbox1_KeyUp(object sender, KeyEventArgs e) { if (conn.State == ConnectionState.Open) conn.Close(); try { string searchText = bunifuMetroTextbox1.Text.Trim(); if (string.IsNullOrEmpty(searchText)) { // 搜索为空时显示全部数据,调用你的DisplayData方法 DisplayData(); return; } // 拆分搜索文本:分离字母前缀和数字部分 string prefix = new string(searchText.TakeWhile(char.IsLetter).ToArray()); string numberPart = new string(searchText.SkipWhile(char.IsLetter).ToArray()); conn.Open(); string query = @"SELECT TOP 2 * FROM Stock_Entry WHERE Stock_No LIKE @Prefix + '%'"; SqlCommand cmd = new SqlCommand(query, conn); cmd.Parameters.AddWithValue("@Prefix", prefix); // 如果有数字部分,添加Stock_ID的匹配(注意数字部分可能为空,比如只输入MG) if (!string.IsNullOrEmpty(numberPart)) { if (int.TryParse(numberPart, out int id)) { query += " AND Stock_ID = @StockId"; cmd.Parameters.AddWithValue("@StockId", id); } else { // 数字部分无效,返回空结果 dataGridView1.DataSource = new DataTable(); return; } } cmd.CommandText = query; DataTable dt = new DataTable(); SqlDataAdapter da = new SqlDataAdapter(cmd); da.Fill(dt); dataGridView1.DataSource = dt; // 同样处理列合并显示 foreach (DataGridViewRow row in dataGridView1.Rows) { if (!row.IsNewRow) { string sNo = row.Cells["Stock_No"].Value.ToString(); int sId = int.Parse(row.Cells["Stock_ID"].Value.ToString()); string itemNo = string.Format("{0}{1:D3}", sNo, sId); row.Cells[0].Value = itemNo; } } } catch (Exception ex) { MessageBox.Show($"搜索出错:{ex.Message}"); } finally { if (conn.State == ConnectionState.Open) conn.Close(); } }
额外的优化建议
- 避免SQL注入:你原来的代码直接拼接用户输入到SQL语句里,这是非常危险的,一定要用参数化查询,上面的代码已经修复了这个问题。
- 统一数据绑定方式:你的
DisplayData方法是手动添加行,而搜索时用DataSource,这可能导致GridView的列显示不一致。建议统一用DataSource的方式,然后通过CellFormatting事件来处理列的合并显示,这样更简洁:// 在Form的构造函数或者GridView初始化时绑定CellFormatting事件 dataGridView1.CellFormatting += DataGridView1_CellFormatting; private void DataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) { // 假设第一列是要显示ItemNo的列 if (e.ColumnIndex == 0 && e.RowIndex >= 0 && !dataGridView1.Rows[e.RowIndex].IsNewRow) { string sNo = dataGridView1.Rows[e.RowIndex].Cells["Stock_No"].Value?.ToString() ?? ""; if (int.TryParse(dataGridView1.Rows[e.RowIndex].Cells["Stock_ID"].Value?.ToString(), out int sId)) { e.Value = string.Format("{0}{1:D3}", sNo, sId); e.FormattingApplied = true; } } } - 不要空catch块:你的
DisplayData里的catch是空的,这样出错了根本不知道哪里有问题,一定要添加异常处理逻辑,比如提示用户或者记录日志。
内容的提问来源于stack exchange,提问作者Nimo
相关产品推荐
相关产品推荐

