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

存储过程spNewSale多表插入行数异常,无需拆分如何实现预期逻辑

问题根因

你当前的存储过程单次仅支持单条商品明细处理,推测你是在前端循环遍历DataGridView行多次调用该存储过程,才会导致orders、payments表重复插入和库存重复扣减的问题。无需拆分存储过程,通过表值参数(TVP) 批量传递所有商品明细即可实现需求:

第一步:创建自定义表值类型

先在数据库中执行以下语句,创建用于传递订单明细的自定义表类型:

CREATE TYPE OrderLineType AS TABLE
(
    product_id INT,
    quantity INT
);

第二步:修改存储过程逻辑

修改后的存储过程仅会执行1次订单插入、1次支付记录插入,批量处理明细插入和库存扣减,同时增加事务保证操作原子性,避免中间出错产生脏数据:

CREATE PROCEDURE spNewSale
    @customer INT, -- 从下拉框传入的客户ID
    @staff VARCHAR(12), -- 当前登录的用户名
    @OrderLines OrderLineType READONLY -- 传入整个DataGridView的所有商品明细
AS
BEGIN
    SET NOCOUNT ON;
    BEGIN TRANSACTION;
    BEGIN TRY
        -- 1. 仅插入1次订单主记录
        INSERT INTO orders (order_cust_id, order_staff_id, order_date)
        VALUES (@customer, 
                (SELECT logon_st_id FROM logons WHERE logon_name = @staff), 
                CURRENT_TIMESTAMP);
        DECLARE @ordernbr INT = SCOPE_IDENTITY();

        -- 2. 批量插入所有订单明细
        INSERT INTO orderlines (ol_order_id, ol_pro_id, ol_qty, ol_value)
        SELECT 
            @ordernbr, 
            ol.product_id, 
            ol.quantity, 
            ol.quantity * p.pro_price
        FROM @OrderLines ol
        INNER JOIN products p ON ol.product_id = p.pro_id;

        -- 3. 批量扣减对应商品库存
        UPDATE p
        SET p.pro_stock = p.pro_stock - ol.quantity
        FROM products p
        INNER JOIN @OrderLines ol ON p.pro_id = ol.product_id;

        -- 4. 仅插入1次支付记录
        INSERT INTO payments (paym_order_id, paym_amount, paym_taken_by, paym_date)
        VALUES (
            @ordernbr,
            (SELECT SUM(ol_value) FROM orderlines WHERE ol_order_id = @ordernbr),
            (SELECT logon_st_id FROM logons WHERE logon_name = @staff),
            CURRENT_TIMESTAMP
        );

        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION;
        -- 抛出错误方便前端排查问题
        THROW;
    END CATCH
END

第三步:前端调用适配(C#示例)

调用时无需循环遍历DataGridView,直接将所有行转为DataTable作为参数传入即可:

// 构造和表值类型结构一致的DataTable
DataTable orderLinesDt = new DataTable();
orderLinesDt.Columns.Add("product_id", typeof(int));
orderLinesDt.Columns.Add("quantity", typeof(int));

// 遍历DataGridView填充明细数据
foreach (DataGridViewRow row in dataGridView1.Rows)
{
    if (!row.IsNewRow)
    {
        orderLinesDt.Rows.Add(
            Convert.ToInt32(row.Cells["你的产品ID列名"].Value),
            Convert.ToInt32(row.Cells["你的数量列名"].Value)
        );
    }
}

// 调用存储过程
using (SqlConnection conn = new SqlConnection("你的数据库连接字符串"))
{
    conn.Open();
    using (SqlCommand cmd = new SqlCommand("spNewSale", conn))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@customer", 选中的客户ID);
        cmd.Parameters.AddWithValue("@staff", 当前登录用户名);
        // 添加表值参数
        SqlParameter tvpParam = cmd.Parameters.AddWithValue("@OrderLines", orderLinesDt);
        tvpParam.SqlDbType = SqlDbType.Structured;
        tvpParam.TypeName = "OrderLineType";
        
        cmd.ExecuteNonQuery();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 03:45:00