Сопоставление пополнения с требованием на основе значения поля - SQL Server - PullRequest
0 голосов
/ 17 июня 2019

Я пытаюсь найти, какое «пополнение» (положительное количество транзакции) может быть сопоставлено с «требованием» (отрицательное количество транзакции).

Основная логика будет такой: Для данного требования,найти первое доступное пополнение (будь то пополнение из существующего инвентаря или из предстоящего изменения).

Я работаю с таблицей 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        |

который создается в результате этого вопроса .

Я сейчас пытаюсь отследить, какой Make_Order выполнит, какой Sale, отследив Transaction_Quantity.

В идеале результирующий набор данных должен выглядеть следующим образом, где Replenishing и Replenishing_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. . Затем сопоставьте пополнения с требованиями на основе Transaction_Date в порядке ASC

Я очень запутался в том, как этого добиться.Я полагаю, что некоторый псевдокод будет выглядеть примерно так:

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

Прямо сейчас, у меня есть это, но я знаю, что он не будет работать.Я очень смущен тем, куда идти отсюда.Я пытался посмотреть на сообщения , как это , но на это не было ответа.Затем я попытался найти 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 Ответ

1 голос
/ 19 июня 2019

Вот одна попытка.Вам нужно будет изменить его с помощью другого уровня абстракции для смещений, если вам необходимо поддерживать увеличение / уменьшение транзакций> 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
...