在不使用 SQL 游标的情况下插入行和更新表

Posted

技术标签:

【中文标题】在不使用 SQL 游标的情况下插入行和更新表【英文标题】:Inserting Rows and Updating a Table without using SQL Cursor 【发布时间】:2011-06-16 02:00:12 【问题描述】:

我正在尝试创建一个 MS SQL 2005 存储过程,以便为订单中的特定组件从仓库分配库存。有多批库存可用,并且必须按特定顺序使用。我可以遍历可用库存并进行分配,直到订单完成,但我试图更多地考虑基于集合而不是顺序,并避免使用 CURSOR。

这是我的查询,用于获取可用于特定订单组件的仓库库存;

SELECT 
        STOCK.ComponentId,
        STOCK.StockId,
        STOCK.ExpiryDate, 
        STOCK.BatchNo, 
        STOCK.StockQty, 
        ORDER_ITEMS.OrderQty        
    FROM 
        STOCK 
        JOIN ORDER_ITEMS ON ORDER_ITEMS.ComponentId = STOCK.ComponentId 
    WHERE 
        STOCK.WarehouseId = @WarehouseId 
        AND STOCK.StockQty > 0
        AND ORDER_ITEMS.OrderItemId = @OrderItemId

我一直将它放入临时表或使用查询创建 CTE 并应用 ORDER BY 子句以在需要用完时对库存进行排序。这给了我一个类似的结果集:

ComponentId | StockId | ExpiryDate | BatchNo  | StockQty | OrderQty
-------------------------------------------------------------------
359         | 3107    | 2013-10-01 | 132435-1 | 20       | 50
359         | 3215    | 2013-10-01 | 154558-1 | 100      | 50
359         | 3216    | 2014-01-01 | 154689-1 | 100      | 50

我需要做的是将记录插入到STOCK_ALLOCATED 表中,使用尽可能多的库存批次来满足订单数量。在上面的示例中,我将使用第一行中的所有 20 个,然后需要第二行中的 30 个。

这需要在STOCK_ALLOCATED 表中插入两条记录,其中OrderItemIdStockId 和两个已用批次的数量(20 和30),同时减少STOCK 表中的库存数量适当的。

假设必要的事务已经到位以始终如一地维护库存表,有没有一种方法可以在不使用 CURSOR 循环并跟踪我已经分配多少库存以及我还需要多少库存的情况下进行插入和更新?

【问题讨论】:

【参考方案1】:

这是一个适合您的测试样本:

SELECT  
    StockID,
    Quantity
FROM (
    SELECT  
        StockID,
        CASE 
            WHEN OrderQty - PreviousQty <= 0 THEN 0
        ELSE 
                CASE 
                    WHEN OrderQty - PreviousQty <= Stock 
                    THEN OrderQty - PreviousQty 
                ELSE
                    Stock 
                END
        END Quantity
    FROM (
        SELECT  
            a.StockID,
            a.Stock,
            a.OrderQty,
            a.OrderByField,
            ISNULL(SUM(b.Stock), 0) PreviousQty
        FROM    
            @Table a
            LEFT JOIN @Table b ON a.OrderByField > b.OrderByField
        GROUP BY a.StockID,
            a.Stock,
            a.OrderQty,
            a.OrderByField
        ) Orders
    ) Orders
WHERE   Quantity > 0

基本上,您需要将自己获得的结果加入其中,这样您就可以将先前保留数量的数量相加,然后从 StockQty 中减去该数量,以确定您还需要完成什么。

不过,为了做到这一点,您将需要一个唯一的 OrderByField,以便您可以准确地过滤掉以前的 StockQty 值。如果您没有可以使用的存储值,则可以使用ROW_NUMBER() OVER 派生它。如果是这种情况,请告诉我您是否需要帮助。

【讨论】:

以上是关于在不使用 SQL 游标的情况下插入行和更新表的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用游标的情况下一次将查询结果分配给多个变量?

如何在不修改数据库模式的情况下仅使用 PL/SQL 更新具有大值的 CLOB?

如何在不使用 CONFLICT_REPLACE 的情况下获得“插入或更新”行为?

在不使用 if 的情况下插入/更新 std::unordered_map 元素的最快方法是啥?

如何使用 Java Spring Boot 在不插入新值的情况下更新表中的现有值

在不使用循环但使用游标的情况下穿越 NSArray?