Home > database >  SQL Percentage increase/decrease
SQL Percentage increase/decrease

Time:07-05

I've attempted to work out percentage increases/decreases but it doesn't seem to be calculating it correctly. You can see in column 4 where I've attempted this. I've tried other ways of doing this by researching on stackoverflow, but without luck.

I get:

| Itemcode X | Current day orders = 4 | Previous sales = 10 | % Change = -98% |

% change should read -60%

Can someone please shed light where I am going wrong please?

Thanks.

Here is my MSSQL query:

SELECT OITM.itemcode, 
round(isnull(FO.[QTY ORDERED],0),0) as "Current Day Orders ",
round(isnull(PSO.[QTY PST ORDERED],0),0) as "Previous Sales",
round(isnull(PSO.[QTY PST ORDERED]-(FO.[QTY ORDERED])*100,0)/FO.[QTY ORDERED],0) as "% Change"
FROM OITM LEFT JOIN
                (
                 SELECT RDR1.itemcode, SUM(Quantity) "QTY ORDERED" FROM RDR1 left join ORDR ON RDR1.DocEntry = ORDR.DocEntry
                 WHERE 
                 ORDR.DocDate >= DATEADD(minute, 0, 
                 CAST(FLOOR(CAST(CURRENT_TIMESTAMP AS float)) AS datetime)
                 ) AND CANCELED = 'N'
                 GROUP BY RDR1.itemcode
                 ) AS "FO" ON OITM.itemcode = FO.itemcode
LEFT JOIN
                (
                SELECT itemcode, SUM(Quantity)/22 "QTY PST ORDERED" FROM RDR1 left join ORDR ON RDR1.DocEntry = ORDR.DocEntry
                WHERE
                ORDR.DocDate >= DATEADD(minute, 0, 
                CAST(FLOOR(CAST(CURRENT_TIMESTAMP AS float)) AS datetime)   
                ) -22 AND CANCELED = 'N'
                GROUP BY RDR1.itemcode
                ) AS "PSO" ON OITM.ItemCode = PSO.ItemCode```

CodePudding user response:

You can try this one:

SELECT OITM.ITEMCODE,
       round(isnull(FO.[QTY ORDERED],0),0) as Current_Day_Orders,
       round(isnull(PSO.[QTY PST ORDERED],0),0) as Previous_Sales,
       /* The expression for "% Change" updated.*/ 
       round(isnull((FO.[QTY ORDERED]-PSO.[QTY PST ORDERED])*100,0)/isnull(PSO.[QTY PST ORDERED],1),0) as "% Change"
  FROM OITM 
  LEFT JOIN (SELECT RDR1.itemcode, SUM(Quantity) "QTY ORDERED" 
               FROM RDR1 
               left join ORDR ON RDR1.DocEntry = ORDR.DocEntry
              WHERE ORDR.DocDate >= DATEADD(minute, 0, CAST(FLOOR(CAST(CURRENT_TIMESTAMP AS float)) AS datetime)) AND CANCELED = 'N'
             GROUP BY RDR1.itemcode) AS "FO" 
    ON OITM.itemcode = FO.itemcode
  LEFT JOIN (SELECT itemcode, SUM(Quantity)/22 "QTY PST ORDERED" 
               FROM RDR1 
               left join ORDR 
                 ON RDR1.DocEntry = ORDR.DocEntry
              WHERE ORDR.DocDate >= DATEADD(minute, 0, CAST(FLOOR(CAST(CURRENT_TIMESTAMP AS float)) AS datetime)) -22 AND CANCELED = 'N'
              GROUP BY RDR1.itemcode) AS "PSO" 
    ON OITM.ItemCode = PSO.ItemCode

CodePudding user response:

To endorse my comment above: Here I'm just isolating the problem, ignoring any possibly necessary joins, and just having the minimal input columns: the item code, a date, and an order quantity:

WITH
-- have some data to play with - not part of final query ..
indata(itemcode,dt,orderqty) AS (
            SELECT 42,'2022-02-01',10
  UNION ALL SELECT 42,'2022-02-02', 4
  UNION ALL SELECT 43,'2022-02-01',20
  UNION ALL SELECT 43,'2022-02-02', 8
  UNION ALL SELECT 44,'2022-02-01',30
  UNION ALL SELECT 44,'2022-02-02',12
)
-- end of input data - real query starts here ...
SELECT
  itemcode
, dt
, orderqty
, LAG(orderqty) OVER(PARTITION BY itemcode ORDER BY dt) AS prev_qty
, CAST (
     (orderqty - LAG(orderqty) OVER(PARTITION BY itemcode ORDER BY dt)) 
    * 100 
    / LAG(orderqty) OVER(PARTITION BY itemcode ORDER BY dt) 
  AS INTEGER
  ) AS chg_pct
FROM indata
ORDER BY 1,2;

 itemcode |     dt     | orderqty | prev_qty | chg_pct 
---------- ------------ ---------- ---------- ---------
       42 | 2022-02-01 |       10 |   (null) |  (null)
       42 | 2022-02-02 |        4 |       10 |     -60
       43 | 2022-02-01 |       20 |   (null) |  (null)
       43 | 2022-02-02 |        8 |       20 |     -60
       44 | 2022-02-01 |       30 |   (null) |  (null)
       44 | 2022-02-02 |       12 |       30 |     -60

CodePudding user response:

The problems:

  • Priority of operation means that * and / is taken into account before the -
  • Additionally you are confusing your variables (they are inverted in the formula)

Fixing these two should give you the correct value

Critical additional problems:

  • Be careful of division by 0 if sales of previous day 0. The current version will crash
  • You correctly check for null in the first to statements, but you don't in the third one, therefore if your previous or current sales are null, the code will still crash

The code suggested by the other user fixes the two first issues, but not the two additional I highlighted, which means your code will crash on null or 0 values

  •  Tags:  
  • sql
  • Related