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

求助:如何按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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:49:28