根据字段值将补货映射到需求-SQL Server

时间:2019-06-17 17:31:56

标签: sql sql-server sql-order-by

我试图找到可以与“需求”(负交易量)相匹配的“补货”(交易量为正)。

基本逻辑是:对于给定的需求,找到第一个可用的补货(该补货是来自现有库存还是来自即将发生的变更)。

我正在使用如下所示的表dbo_purchases_new

| Element_ID |   Element  | Transaction_Date | Transaction_Quantity | Total_Inventory |
|:----------:|:----------:|:----------------:|:--------------------:|:---------------:|
|            |    STOCK   |                  |           5          |        5        |
|    MO302   | Make_Order |     1/3/2019     |           1          |        6        |
|    SO105   |    Sale    |     2/1/2019     |          -1          |        5        |
|    SO106   |    Sale    |     2/1/2019     |          -1          |        4        |
|    MO323   | Make_Order |     2/2/2019     |           1          |        5        |
|    SO107   |    Sale    |     2/4/2019     |          -1          |        4        |
|    SO191   |    Sale    |     2/5/2019     |          -1          |        3        |
|    SO123   |    Sale    |     2/6/2019     |          -1          |        2        |
|    SO166   |    Sale    |     3/1/2019     |          -1          |        1        |
|    SO819   |    Sale    |     3/5/2019     |          -1          |        0        |
|    SO603   |    Sale    |     3/10/2019    |          -4          |        -3       |
|    MO400   | Make_Order |     3/15/2019    |           1          |        -2       |
|    MO459   | Make_Order |     3/15/2019    |           1          |        -1       |
|    MO460   | Make_Order |     3/18/2019    |           1          |        0        |
|    MO491   | Make_Order |     3/19/2019    |           1          |        1        |
|    MO715   | Make_Order |     4/1/2019     |           3          |        4        |
|    SO100   |    Sale    |     4/2/2019     |          -1          |        3        |
|    SO322   |    Sale    |     4/3/2019     |          -1          |        2        |
|    SO874   |    Sale    |     4/4/2019     |          -1          |        1        |
|    SO222   |    Sale    |     4/5/2019     |          -1          |        0        |
|    MO999   | Make_Order |     4/5/2019     |           1          |        1        |
|    SO999   |    Sale    |     4/6/2019     |          -1          |        0        |
this question创建的

我现在正尝试通过跟踪Make_Order来跟踪哪个Sale将履行哪个Transaction_Quantity

理想情况下,结果数据集将如下所示,其中Replenishment和Replenishment_Date是新添加的列:

| Element_ID |   Element  | Transaction_Date | Transaction_Quantity | Total_Inventory | Replenishment | Replenishment_Date |
|:----------:|:----------:|:----------------:|:--------------------:|:---------------:|:-------------:|:------------------:|
|            |    STOCK   |                  |           5          |        5        |      NULL     |        NULL        |
|    MO302   | Make_Order |     1/3/2019     |           1          |        6        |      NULL     |        NULL        |
|    SO105   |    Sale    |     2/1/2019     |          -1          |        5        |     STOCK     |        NULL        |
|    SO106   |    Sale    |     2/1/2019     |          -1          |        4        |     STOCK     |        NULL        |
|    MO323   | Make_Order |     2/2/2019     |           1          |        5        |      NULL     |        NULL        |
|    SO107   |    Sale    |     2/4/2019     |          -1          |        4        |     STOCK     |        NULL        |
|    SO191   |    Sale    |     2/5/2019     |          -1          |        3        |     STOCK     |        NULL        |
|    SO123   |    Sale    |     2/6/2019     |          -1          |        2        |     STOCK     |        NULL        |
|    SO166   |    Sale    |     3/1/2019     |          -1          |        1        |     MO302     |      1/3/2019      |
|    SO819   |    Sale    |     3/5/2019     |          -1          |        0        |     MO323     |      2/2/2019      |
|    SO603   |    Sale    |     3/10/2019    |          -4          |        -3       |     MO460     |      3/18/2019     |
|    MO400   | Make_Order |     3/15/2019    |           1          |        -2       |      NULL     |        NULL        |
|    MO459   | Make_Order |     3/15/2019    |           1          |        -1       |      NULL     |                    |
|    MO460   | Make_Order |     3/18/2019    |           1          |        0        |      NULL     |        NULL        |
|    MO491   | Make_Order |     3/19/2019    |           1          |        1        |      NULL     |        NULL        |
|    MO715   | Make_Order |     4/1/2019     |           3          |        4        |      NULL     |        NULL        |
|    SO100   |    Sale    |     4/2/2019     |          -1          |        3        |     MO491     |      3/19/2019     |
|    SO322   |    Sale    |     4/3/2019     |          -1          |        2        |     MO715     |      4/1/2019      |
|    SO874   |    Sale    |     4/4/2019     |          -1          |        1        |     MO715     |      4/1/2019      |
|    SO222   |    Sale    |     4/5/2019     |          -1          |        0        |     MO715     |      4/1/2019      |
|    MO999   | Make_Order |     4/5/2019     |           1          |        1        |      NULL     |        NULL        |
|    SO999   |    Sale    |     4/6/2019     |          -1          |        0        |     SO999     |      4/5/2019      |

规则集实质上是: 对于给定的需求(任意值的负交易量),找到哪个补货(任意值的正交易量)满足要求。

  1. 将库存分配到第一个需求,直到用完为止。注意 -可能是不存在库存的情况,因此仅在库存确实存在的情况下适用
  2. 然后,根据 ASC订单中的Transaction_Date

我对如何实现这一目标感到非常困惑。我想一些伪代码看起来像:

for curr in transaction_quantity:
    if curr < 0:
        if stock.exists() and stock.notempty():
          fill in data from that
        else:
            find next replenishment
            fill in data from that
    else:
        next

现在,到目前为止,我已经知道了,但是我知道它不会运行。我对从这里去哪里很困惑。我尝试查看帖子like this,但没有答案。然后我tried looking up CURSOR,但这令我感到困惑,我不确定如何将其应用于此问题。

/****** WiP Script  ******/
SELECT 
    [jerry].[dbo].[purchases_new].*,
    CASE WHEN Transaction_Quantity < 0 THEN -- (SELECT Element_ID FROM the_current_row WHERE transaction_quantity > 0)
    ELSE NULL AS "Replenishment",
    -- (SELECT Transaction_Date FROM [jerry].[dbo].[purchases_new] WHERE Element_ID 
    -- Not sure how to grab the correct date of the element id from the column before
FROM 
    [jerry].[dbo].[purchases_new]

感谢您的协助。我一直在努力解决这个问题。注释包含其他信息。 注意-由于用户要求提供更多信息,我一直在尝试更新此问题。

1 个答案:

答案 0 :(得分:1)

这是一次尝试。如果您需要支持> 1的交易增量/减量,则需要使用另一层抽象来进行抵消。它基本上使销售顺序与借方顺序对齐,然后将其用作连接回到主数据集。

Sql Fiddle

想法是将加法和减法分为两组,按组先后顺序排列,同时还要记住每个项目的顺序回到主列表中。这样,您可以将每个减法与最近的加法对齐。在处理1时,这非常简单。

编辑->处理值> 1。

计算Transaction_Amount>(+/-)1会增加一点复杂度,但仍然可以解决。现在,我们需要扩展由Transaction_Amount设置的每个加减交易,因此将数据集加长,但是,原始算法仍将应用于现在更长的数据集。这将允许记录“部分完成”。因此(12 A 5)等于(12 A 1), (12 A 1), (12 A 1), (12 A 1), (12 A 1)。现在,当减法器以类似的方式加长时(所有行的顺序与序列的第一个相同),对齐仍然有效,并且加法和减法可以与最近的邻居进行匹配。

DECLARE @T TABLE(Element_ID NVARCHAR(50),Element NVARCHAR(50), Transaction_Date DATETIME,Transaction_Quantity INT,Total_Inventory INT)
INSERT @T VALUES
('MO301','Make_Order','1/1/2019',5,1),
('MO302','Make_Order','1/3/2019',1,2),
('SO105','Sale','2/1/2019',-2,1),
('SO106','Sale','2/1/2019',-1,0),
('MO323','Make_Order','2/2/2019',1,1),
('SO107','Sale','2/4/2019',-1,0),
('SO191','Sale','2/5/2019',-1,-1),
('SO123','Sale','2/6/2019',-1,-2),
('SO166','Sale','3/1/2019',-1,-3),
('SO603','Sale','3/2/2019',-1,-4),
('MO400','Make_Order','3/15/2019',1,-3),
('MO459','Make_Order','3/15/2019',1,-2),
('MO460','Make_Order','3/18/2019',1,-1),
('MO491','Make_Order','3/19/2019',1,0)


;WITH Normalized AS
(
    SELECT *, RowNumber = ROW_NUMBER() OVER (ORDER BY (SELECT 0)), IsAdd = CASE WHEN Transaction_Quantity>0 THEN 1 ELSE 0 END FROM @T
)

,ReplicateAmount AS
 (
    SELECT  Element_ID, Element, Transaction_Date, Transaction_Quantity=ABS(Transaction_Quantity) ,Total_Inventory, RowNumber, IsAdd
    FROM Normalized

    UNION ALL

    SELECT R.Element_ID, R.Element, R.Transaction_Date, Transaction_Quantity=(R.Transaction_Quantity - 1), R.Total_Inventory, R.RowNumber, R.IsAdd
    FROM ReplicateAmount R INNER JOIN Normalized N ON R.RowNumber = N.RowNumber
    WHERE ABS(R.Transaction_Quantity) > 1
)
,NormalizedAgain AS
(
    SELECT Element_ID, Element, Transaction_Date, Transaction_Quantity=1, Total_Inventory, RowNumber = ROW_NUMBER() OVER (ORDER BY RowNumber), IsAdd FROM ReplicateAmount
)
,Additives AS
(
    SELECT *, AddedOrder = ROW_NUMBER() OVER (ORDER BY (SELECT 0)) FROM NormalizedAgain WHERE  IsAdd=1
)
,Subtractions AS
(
    SELECT Element_ID, Element, Transaction_Date, Transaction_Quantity=-1 , Total_Inventory, RowNumber,  SubtractedOrder = ROW_NUMBER() OVER (ORDER BY (SELECT 0))FROM NormalizedAgain  WHERE IsAdd=0
)
,WithTies AS
(
    SELECT 
        S.RowNumber,
        S.Element_ID,
        BoughtFromRowNumber = A.RowNumber,
        SoldToID =S.Element_ID,
        BoughFromID=A.Element_ID,
        S.Element,
        S.Transaction_Date,
        S.Transaction_Quantity,
        S.Total_Inventory
    FROM 
        Additives A
        LEFT OUTER JOIN  Subtractions S ON A.AddedOrder=S.SubtractedOrder 

    UNION  

    SELECT 
        A.RowNumber,
        A.Element_ID,
        BoughtFromRowNumber = S.RowNumber,
        SoldToID = NULL,
        BoughFromID=NULL,
        A.Element,
        A.Transaction_Date,
        A.Transaction_Quantity,
        A.Total_Inventory
    FROM 
        Additives A
        LEFT OUTER JOIN  Subtractions S ON A.AddedOrder=S.SubtractedOrder 
)
SELECT 
    T.RowNumber,
    T.Element_ID,
    T.Element,
    T.Transaction_Date,
    T.Transaction_Quantity,
    T.Total_Inventory,
    T2.SoldToID,
    T.BoughFromID
FROM 
    WithTies T
    LEFT OUTER JOIN WithTies T2 ON T2.BoughtFromRowNumber= T.RowNumber  
WHERE
    NOT T.RowNumber IS NULL
ORDER BY 
    T.RowNumber