SQL Running Subtraction

2019-08-02 03:52发布

问题:

Just a brief of business scenario is table has been created for a good receipt. So here we have good expected line with PurchaseOrder(PO) in first few line. And then we receive each expected line physically and that time these quantity may be different, due to business case like quantity may damage and short quantity like that. So we maintain a status for that eg: OK, Damage, also we have to calculate short quantity based on total of expected quantity of each item and total of received line.

    if object_id('DEV..Temp','U') is not null
    drop table Temp

    CREATE TABLE Temp 
    (        
    ID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,        
    Item VARCHAR(32),
    PO VARCHAR(32) NULL,        
    ExpectedQty INT NULL,
    ReceivedQty INT NULL,
    [STATUS] VARCHAR(32) NULL,
    BoxName VARCHAR(32) NULL
    )

Please see first few line with PO data will be the expected lines, and then rest line will be received line

    INSERT INTO TEMP (Item,PO,ExpectedQty,ReceivedQty,[STATUS],BoxName)
    SELECT 'ITEM01','PO-01','30',NULL,NULL,NULL UNION ALL 
    SELECT 'ITEM01','PO-02','20',NULL,NULL,NULL UNION ALL 
    SELECT 'ITEM02','PO-01','40',NULL,NULL,NULL UNION ALL 
    SELECT 'ITEM03','PO-01','50',NULL,NULL,NULL UNION ALL 
    SELECT 'ITEM03','PO-02','30',NULL,NULL,NULL UNION ALL 
    SELECT 'ITEM03','PO-03','20',NULL,NULL,NULL UNION ALL 
    SELECT 'ITEM04','PO-01','30',NULL,NULL,NULL UNION ALL 
    SELECT 'ITEM01',NULL,NULL,'20','OK','box01' UNION ALL 
    SELECT 'ITEM01',NULL,NULL,'25','OK','box02' UNION ALL 
    SELECT 'ITEM01',NULL,NULL,'5','DAMAGE','box03' UNION ALL 
    SELECT 'ITEM02',NULL,NULL,'38','OK','box04' UNION ALL 
    SELECT 'ITEM02',NULL,NULL,'2','DAMAGE','box05' UNION ALL 
    SELECT 'ITEM03',NULL,NULL,'30','OK','box06' UNION ALL 
    SELECT 'ITEM03',NULL,NULL,'30','OK','box07' UNION ALL 
    SELECT 'ITEM03',NULL,NULL,'30','OK','box08' UNION ALL 
    SELECT 'ITEM03',NULL,NULL,'10','DAMAGE','box09' UNION ALL
    SELECT 'ITEM04',NULL,NULL,'25','OK','box10' 

Below Table is my expected result based on above data. I need to show those data following way. So I appreciate if you can give me an appropriate query for it. Note: first row is blank and it is actually my table header. :)

    SELECT  '' as 'ITEM', '' as 'PO#', '' as 'ExpectedQty',
            '' as 'ReceivedQty','' as 'DamageQty' ,'' as 'ShortQty' UNION ALL 
    SELECT 'ITEM01','PO-01','30','30','0' ,'0'  UNION ALL 
    SELECT 'ITEM01','PO-02','20','15','5' ,'0'  UNION ALL 
    SELECT 'ITEM02','PO-01','40','38','2' ,'0'  UNION ALL 
    SELECT 'ITEM03','PO-01','50','50','0' ,'0'  UNION ALL 
    SELECT 'ITEM03','PO-02','30','30','0' ,'0'  UNION ALL 
    SELECT 'ITEM03','PO-03','20','10','10','0' UNION ALL 
    SELECT 'ITEM04','PO-01','30','25','0' ,'5'  

Note : we don't received more than expected. solution should be based on SQL 2000

回答1:

You should reconsider how you store this data. Separate Expected and Received+Damaged in different tables (you have many unused (null) cells). This way any query should become more readable.

I think what you try to do can be achieved more easily with a stored procedure.

Anyway, try this query:

SELECT Item, PO, ExpectedQty, 
       CASE WHEN [rec-consumed] > 0 THEN ExpectedQty 
            ELSE CASE WHEN [rec-consumed] + ExpectedQty > 0
                      THEN [rec-consumed] + ExpectedQty
                      ELSE 0
                 END
       END ReceivedQty,
       CASE WHEN [rec-consumed] < 0
                 THEN CASE WHEN DamageQty >= -1*[rec-consumed]
                           THEN -1*[rec-consumed]
                           ELSE DamageQty
                      END
            ELSE 0
       END DamageQty,
       CASE WHEN [rec_damage-consumed] < 0
            THEN DamageQty - [rec-consumed]
            ELSE 0
       END ShortQty
FROM (
    select t1.Item,
           t1.PO,
           t1.ExpectedQty,
           st.sum_ReceivedQty_OK 
                  - (sum(COALESCE(t2.ExpectedQty,0)) 
                     +t1.ExpectedQty)
               [rec-consumed],
           st.sum_ReceivedQty_OK + st.sum_ReceivedQty_DAMAGE
                  - (sum(COALESCE(t2.ExpectedQty,0))
                     +t1.ExpectedQty)
               [rec_damage-consumed],
           st.sum_ReceivedQty_DAMAGE DamageQty
    from #tt t1
    left join #tt t2 on t1.Item = t2.Item
                    and t1.PO > t2.PO
                    and t2.PO is not null
    join (select Item
           , sum(CASE WHEN status = 'OK' THEN ReceivedQty ELSE 0 END)
                 sum_ReceivedQty_OK
           , sum(CASE WHEN status != 'OK' THEN ReceivedQty ELSE 0 END)
                 sum_ReceivedQty_DAMAGE
        from #tt where PO is null
        group by Item) st on t1.Item = st.Item
    where t1.PO is not null
    group by t1.Item, t1.PO, t1.ExpectedQty,
             st.sum_ReceivedQty_OK,
             st.sum_ReceivedQty_DAMAGE
) a
order by Item, PO