如何计算SQL查询中3年以上的价格变化

时间:2014-03-18 13:50:59

标签: sql oracle

我需要计算过去三年中某个项目的价格变化(包括成本和变化百分比)。

该表有四个字段:

SKU_no, Date_updated, Price, Active_flag

Active_flag字段为A时,该项处于有效状态,而I处于非活动状态时。有些项目的年份没有改变价格,所以他们没有三年的非活动旗帜参赛作品。

样本表

      SKU_NO       Update_date        Price        Active_flag
      30           1/1/1999           40.8            I
      33           1/1/2014           70.59           A
      33           1/1/2013           67.23           I
      33           1/1/2012           60.03           I
      33           1/1/2011           55.08           I
      33           1/1/2010           55.08           I
      34           1/1/2009           51              A
      36           1/1/2014           70.59           A
      36           1/1/2013           67.23           I
      36           1/1/2012           60.03           I
      38           1/1/2002           43.32           A
      38           1/1/2001           43.32           I
      38           4/8/2000           43.32           I
      38           1/1/1999           43.32           I
      39           1/1/2014           73.08           A
      39           1/1/2013           69.6            I
      39           1/1/2012           62.13           I
      39           1/1/2011           57              I
      39           1/1/2010           57              I
      39           1/1/2009           52.8            I

这是我写的第一个查询。我不太熟悉复杂的计算

select 
    s.VENDOR,
    s.FISCAL_YEAR,
    s.FISCAL_MONTH_NO,
    s.FISCAL_YEAR||'_'||FISCAL_MONTH_NO as PERIOD, 
CASE WHEN S.COST_USED_FLAG IN ('CONTRACT') THEN 'CONTRACT' ELSE 'NON-CONTRACT' END AS CONTRACT_TYPE,
CASE WHEN ((s.FISCAL_YEAR = 2014 AND FISCAL_MONTH_NO <=9) OR (FISCAL_YEAR = 2013 AND FISCAL_MONTH_NO >=10)) THEN 'CP_1'
     WHEN ((s.FISCAL_YEAR = 2013 AND FISCAL_MONTH_NO <= 9) OR (FISCAL_YEAR = 2012 AND FISCAL_MONTH_NO >=10)) THEN 'CP_2'
     WHEN ((s.FISCAL_YEAR = 2012 AND FISCAL_MONTH_NO <= 9) OR (FISCAL_YEAR = 2011 AND FISCAL_MONTH_NO >=10)) THEN 'CP_3'
     ELSE 'NULL' END CAGR_PERIODS,
    CASE WHEN s.MARKET IN ('PO', 'SC', 'OC') THEN 'PC' ELSE 'EC' END AS MARKET_TYPE,   
    s.MARKET, 
    s.COST_PLUS_FLAG,
    s.COST_USED_FLAG,
    LPAD(S.PC_ITEM_NO,6,'0') AS NEW_ITEM_NO,
    s.PC_ITEM_NO,
    i.ITEM_NO,
    i.VEND_CAT_NUM,
    i.DESCRIPTION,
    s.PC_PROD_CAT,
    s.PC_PROD_SUBCAT,
    i.SELL_UOM,
    i.QTY_PER_SELL_UOM,
    i.PRIMARY_UOM,
    i.HEAD_CONV_FACT,
    SUM(s.QTY_EACH) AS QUANTITY_SOLD, 
    SUM(s.EXT_GROSS_COGS) AS TOTAL_COGS, 
    SUM(s.EXT_GROSS_COGS)/ SUM(s.QTY_EACH) as NET_SALES, 
    SUM(s.EXT_SALES)/ SUM(s.QTY_EACH) as ASP,
    SUM(s.EXT_SALES) AS TOTAL_SALES,
    SUM(S.EXT_SALES) - SUM(S.EXT_GROSS_COGS) as GROSS_PROFIT
    from SIXSIGMA.CIA_ALL_SALES_TREND_DATA  s
    INNER JOIN MGMSH.ITEM i
    ON S.PC_ITEM_NO = I.ITEM_NO
    WHERE S.VENDOR = 'BD' AND
    (S.EXT_SALES IS NOT NULL AND S.FISCAL_YEAR IN ('2013','2012','2011'))
    GROUP BY 
    s.VENDOR,
    s.FISCAL_YEAR,
    s.FISCAL_MONTH_NO, 
    s.FISCAL_YEAR||'_'||FISCAL_MONTH_NO,
    CASE WHEN s.MARKET IN ('PO', 'SC', 'OC') THEN 'PC' ELSE 'EC' END,
    CASE WHEN S.COST_USED_FLAG IN ('CONTRACT') THEN 'CONTRACT' ELSE 'NON-CONTRACT' END,
    CASE WHEN ((s.FISCAL_YEAR = 2014 AND FISCAL_MONTH_NO <=9) OR (FISCAL_YEAR = 2013 AND  FISCAL_MONTH_NO >=10)) THEN 'CP_1'
    WHEN ((s.FISCAL_YEAR = 2013 AND FISCAL_MONTH_NO <= 9) OR (FISCAL_YEAR = 2012 AND FISCAL_MONTH_NO >=10)) THEN 'CP_2'
    WHEN ((s.FISCAL_YEAR = 2012 AND FISCAL_MONTH_NO <= 9) OR (FISCAL_YEAR = 2011 AND FISCAL_MONTH_NO >=10)) THEN 'CP_3'
     ELSE 'NULL' END,
    s.MARKET, 
    s.COST_USED_FLAG,
    s.COST_PLUS_FLAG,
    s.PC_ITEM_NO,
    s.PC_PROD_CAT,
    i.SELL_UOM,
    i.QTY_PER_SELL_UOM,
    i.PRIMARY_UOM,
    i.HEAD_CONV_FACT,
    i.DESCRIPTION,
    i.VEND_CAT_NUM,
    s.PC_PROD_SUBCAT,
    i.ITEM_NO
    ORDER BY s.PC_ITEM_NO,s.FISCAL_YEAR, s.FISCAL_MONTH_NO

1 个答案:

答案 0 :(得分:0)

有几种方法可以解决这个问题,但我建议使用窗口函数,例如LAGLEAD。使用这些函数,您可以引用相邻的行。例如:

lead(column, offset, default) over (partition by some_column order by column)

在下面的示例中:

lead(price, 1, price) over (partition by sku_no order by update_date desc)

以下是一个包​​含示例数据的工作示例:

with sample_data as (
      select '30' sku_no, to_date('1/1/1999','DD/MM/YYYY') update_date, 40.8 price, 'I' active_flag from dual union all
      select '33', to_date('1/1/2014','DD/MM/YYYY'), 70.59, 'A' from dual union all
      select '33', to_date('1/1/2013','DD/MM/YYYY'), 67.23, 'I' from dual union all
      select '33', to_date('1/1/2012','DD/MM/YYYY'), 60.03, 'I' from dual union all
      select '33', to_date('1/1/2011','DD/MM/YYYY'), 55.08, 'I' from dual union all
      select '33', to_date('1/1/2010','DD/MM/YYYY'), 55.08, 'I' from dual union all
      select '34', to_date('1/1/2009','DD/MM/YYYY'), 51   , 'A' from dual union all
      select '36', to_date('1/1/2014','DD/MM/YYYY'), 70.59, 'A' from dual union all
      select '36', to_date('1/1/2013','DD/MM/YYYY'), 67.23, 'I' from dual union all
      select '36', to_date('1/1/2012','DD/MM/YYYY'), 60.03, 'I' from dual union all
      select '38', to_date('1/1/2002','DD/MM/YYYY'), 43.32, 'A' from dual union all
      select '38', to_date('1/1/2001','DD/MM/YYYY'), 43.32, 'I' from dual union all
      select '38', to_date('4/8/2000','DD/MM/YYYY'), 43.32, 'I' from dual union all
      select '38', to_date('1/1/1999','DD/MM/YYYY'), 43.32, 'I' from dual union all
      select '39', to_date('1/1/2014','DD/MM/YYYY'), 73.08, 'A' from dual union all
      select '39', to_date('1/1/2013','DD/MM/YYYY'), 69.6 , 'I' from dual union all
      select '39', to_date('1/1/2012','DD/MM/YYYY'), 62.13, 'I' from dual union all
      select '39', to_date('1/1/2011','DD/MM/YYYY'), 57   , 'I' from dual union all
      select '39', to_date('1/1/2010','DD/MM/YYYY'), 57   , 'I' from dual union all
      select '39', to_date('1/1/2009','DD/MM/YYYY'), 52.8 , 'I' from dual)
select
  sku_no,
  update_date,
  price,
  lead(price,1, price) over (partition by sku_no order by update_date desc) prior_price, -- Showing the offset
  price - lead(price,1, price) over (partition by sku_no order by update_date desc) price_difference, -- Calculate the difference 
  round((price - lead(price,1, price) over (partition by sku_no order by update_date desc)) * 100 /price, 2) percent_change -- Calculate the percentage
from sample_data
where update_date >= add_months(trunc(sysdate,'YYYY'),-36); -- You said in the last three years

您还可以按排序使用不同排序的LAG。如果您想计算三年前的差异,我建议使用KEEP函数。