简体   繁体   中英

Return values from Table A to Table B

I need help. Hi guys, I have 2 tables and I want to return the FIRST DueDate and QtyReceive from Table A to Table B if RunningTotalQtyReceive (from Table A) >= RunningTotalQtyShort (from Table B). It returns NULL if QtyReceive/TotalRunningQtyReceive can't cover QtyShort/TotalRunningQtyShort. The dataset has been ordered by Date. RunningTotalQtyReceive and RunningTotalQtyShort have been calculated by Window Function.

SUM(QtyReceive) OVER(PARTITION BY Item ORDER BY DueDate)
SUM(QtyShort) OVER(PARTITION BY Item ORDER BY MatlDueDate)

Table A:

Item     DueDate         QtyReceive   RunningTotalQtyReceive
 A1     2021-10-08            6                6
 A1     2021-10-22            5                11
 A1     2022-02-01            9                20

Table B:

Item    MatlDueDate     QtyShort    RunningTotalQtyShort
 A1      2022-06-01        0                0
 A1      2022-06-03        1                1
 A1      2022-06-04        2                3
 A1      2022-06-05        4                7
 A1      2022-06-06        8                15
 A1      2022-06-07        5                20
 A1      2022-06-08        3                23
 A1      2022-06-09        10               33

Expected Output:

Item    MatlDueDate QtyShort    RunningTotalQtyShort    RunningTotalQtyReceive  DueDate    QtyReceive
 A1     2022-06-01     0                 0                       6             2021-10-08      6
 A1     2022-06-03     1                 1                       6             2021-10-08      6
 A1     2022-06-04     2                 3                       6             2021-10-08      6
 A1     2022-06-05     4                 7                       11            2021-10-22      5
 A1     2022-06-06     8                 15                      20            2022-02-01      9
 A1     2022-06-07     5                 20                      20            2022-02-01      9
 A1     2022-06-08     3                 23                      NULL            NULL          NULL
 A1     2022-06-09     10                33                      NULL              NULL        NULL

This is my script to return the expected output:

SELECT 
     b.*, 
     c.RunningTotalQTyReceive, 
     c.DueDate, 
     c.QtyReceive
FROM TableB b 
OUTER APPLY (SELECT TOP 1 
                a.RunningTotalQTyReceive,
                FIRST_VALUE(DueDate) OVER(ORDER BY DueDate) AS DueDate, 
                a.QtyReceive
             FROM TableA a
             WHERE a.item = b.item
             AND a.RunningTotalQtyReceive >= b.RunningTotalQtyShort
             ) c

The problem is that this is "Triangular" Join ( https://www.sqlservercentral.com/articles/hidden-rbar-triangular-joins#:~:text=A%20Triangular%20Join%20is%20nothing,rows%20spawned%20are%20nearly%20trivial ) which slows down the query execution time. It took me 35 mins to 1 hour to finish the execution with the 200,000-row dataset. Could you please help me with any idea to reduce the time execution? Any other joins or user-defined functions? Thank you a lot. Any help will be appreciated. Please let me know if you need any clarification on my question.

Create TableA:

CREATE TABLE TableA
(
Item varchar(2),
DueDate date,
QtyReceive int,
RunningTotalQtyReceive int
);

INSERT INTO TableA values
('A1',      '10/08/2021',       6,       6),
('A1',      '10/22/2021',       5,      11),
('A1',      '02/01/2022',       9,      20);

Create TableB:

CREATE TABLE TableB
(
Item varchar(2),
MatlDueDate date,   
QtyShort int,
RunningTotalQtyShort int,
);

INSERT INTO TableB values
('A1',      '06/01/2022',         0,         0),
('A1',      '06/03/2022',         1,         1),
('A1',      '06/04/2022',         2,         3),
('A1',      '06/05/2022',         4,         7),
('A1',      '06/06/2022',         8,         15),
('A1',      '06/07/2022',         5,         20),
('A1',      '06/08/2022',         3,         23),
('A1',      '06/09/2022',         10,        33);

You don't need to store the values of RunningTotalQtyReceive and RunningTotalQtyShort, since they can be calculated from the input tables. Try the following to get the desired results:

With CTE1 AS
(
  Select Item, DueDate, QtyReceive,  
         SUM(QtyReceive) OVER(PARTITION BY Item ORDER BY DueDate) AS RunningTotalQtyReceive
  From TableA
),
CTE2 AS
(
 Select Item, MatlDueDate, QtyShort,
        SUM(QtyShort) OVER(PARTITION BY Item ORDER BY MatlDueDate) AS RunningTotalQtyShort
 From TableB
)

Select B.Item, B.MatlDueDate, B.QtyShort, B.RunningTotalQtyShort,
       A.RunningTotalQtyReceive, A.DueDate, A.QtyReceive
From CTE2 B
Left Join
(
  Select Item, DueDate, QtyReceive, RunningTotalQtyReceive, 
         LAG(RunningTotalQtyReceive, 1, 0) Over (Partition By Item Order By DueDate) AS lrtqr
  From CTE1
) A

On B.RunningTotalQtyShort <=  A.RunningTotalQtyReceive and B.RunningTotalQtyShort >=  A.lrtqr
And B.Item = A.Item

See a demo from db<>fiddle .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM