【问题标题】:How to calculate prior year sales data in SQL如何在 SQL 中计算上一年的销售数据
【发布时间】:2019-04-11 00:33:11
【问题描述】:

我正在尝试构建一个按周汇总销售数据的表格。在其中,我试图让相邻的列之一显示上一年同一财政周的销售数据(由于我的组织财政日历,去年有第 53 周)。我还需要将(Comp Units/Comp Sales)与 52 周前的时期进行比较,这是一个完全不同的财政周(想想 2019 年第 9 周与 2018 年第 10 周相比)。

我尝试过同时使用联合和完全外连接,但考虑到我的数据方式,它们效率低下(因为这是每周数据,联合最终效率低下,因为我需要留下日期信息的初始查询,然后更新我的表中的列以反映数据所在的周。这显然充满了出错的机会,而且执行 105 次也很耗时),或者只是没有工作(尝试一个完整的外部join 为所有列返回了错误的答案)。我也尝试过使用 CTE,但这对我也不起作用。我目前正在尝试 CASE 语句,但这也返回了一个空值。我不太确定下一步该去哪里

#STANDARDSQL
SELECT 
 DTL.SKU_NBR                                                      AS SKU_NBR
, SLS.STR_NBR                                                     AS STR_NBR
, CONCAT(TRIM(CAST(SKU_HIER.SKU_NBR AS STRING)), ' ', '-', ' ', TRIM(SKU_HIER.SKU_DESC))                                          AS SKU
, CONCAT(TRIM(CAST(SKU_HIER.EXT_SUB_CLASS_NBR AS STRING)), ' ', '-', ' ', TRIM(SKU_HIER.SUB_CLASS_DESC))                                    AS SUB_CLASS
, CONCAT(TRIM(CAST(SKU_HIER.EXT_SUB_SC_NBR AS STRING)), ' ', '-', ' ', TRIM(SKU_HIER.SUB_SC_DESC))                                 AS SUB_SUB_CLASS
, LOCATION.MKT_NM                                           AS MARKET_NAME
, LOCATION.RGN_NM                                           AS REGION_NAME
, LOCATION.DIV_NM                                           AS DIVISION_NAME
, LOCATION.DIV_NBR                                          AS DIVISION_NUMBER
, LOCATION.RGN_NBR                                          AS REGION_NUMBER
, LOCATION.MKT_NBR                                          AS MARKET_NUMBER
, COMP.STR_COMP_IND                                         AS COMP_IND
, COMP.PY_STR_COMP_IND                                      AS PRIOR_COMP_IND
, CALENDAR.FSCL_WK_DESC                                     AS FISCAL_WEEK
, CALENDAR.FSCL_PRD_DESC                                    AS FISCAL_PERIOD
, CALENDAR.FSCL_WK_END_DT                                   AS END_DATE
, CALENDAR.FSCL_WK_BGN_DT                                   AS BEGIN_DATE
, CALENDAR.FSCL_YR                                          AS FISCAL_YEAR_NBR
, CALENDAR.FSCL_WK_NBR                                      AS WEEK_NUMBER
, CALENDAR.FSCL_YR_WK_KEY_VAL                               AS FISCAL_KEY
, CALENDAR.LY_FYR_WK_KEY_VAL                                AS LY_FISCAL_KEY
, SUM(COALESCE(DTL.UNT_SLS,0))                              AS UNITS
, SUM(COALESCE(DTL.EXT_RETL_AMT,0) + COALESCE(DTL.TOT_GDISC_DTL_AMT,0))                                                                                        
                                                            AS SALES
, SUM(CASE
            WHEN 1=1 THEN (COALESCE(DTL.EXT_RETL_AMT,0) + COALESCE(DTL.TOT_GDISC_DTL_AMT,0)) * COMP.STR_COMP_IND
            ELSE 0 END)                                     AS COMP_SALES
, SUM(CASE
            WHEN 1=1 THEN (COALESCE(DTL.UNT_SLS,0)) * COMP.STR_COMP_IND
            ELSE 0 END)                                     AS COMP_UNITS
, SUM(CASE
            WHEN 1=1 AND SLS.SLS_DT = DATE_SUB(SLS.SLS_DT, INTERVAL 364 DAY) 
            THEN (COALESCE(DTL.EXT_RETL_AMT,0) + 
            COALESCE(DTL.TOT_GDISC_DTL_AMT,0)) * COMP.PY_STR_COMP_IND
            ELSE NULL END)                                                                                                                                                 
                                                            AS LY_COMP_SALES
, SUM(CASE
            WHEN 1=1 AND SLS.SLS_DT = DATE_SUB(SLS.SLS_DT, INTERVAL 364 DAY)  
            THEN (COALESCE(DTL.UNT_SLS,0)) * COMP.PY_STR_COMP_IND
            ELSE NULL END)                                                                                                                                                 
                                                            AS LY_COMP_UNITS
, SUM(CASE 
            WHEN SLS.SLS_DT = DATE_SUB(SLS.SLS_DT, INTERVAL 371 DAY) 
            THEN (COALESCE(DTL.EXT_RETL_AMT,0) + 
            COALESCE(DTL.TOT_GDISC_DTL_AMT,0)) 
            ELSE NULL END)                                                                                                               
                                                            AS LY_SALES
, SUM(CASE 
            WHEN SLS.SLS_DT = DATE_SUB(SLS.SLS_DT, INTERVAL 371 DAY) 
            THEN (COALESCE(DTL.UNT_SLS,0)) 
            ELSE NULL END)                                                                                                               
                                                            AS LY_UNITS


FROM `pr-edw-views.SLS.POS_SLS_TRANS_DTL`                   AS SLS

INNER JOIN 
  UNNEST (SLS.DTL)                                          AS DTL 


JOIN `pr-edw-views.SHARED.MVNDR_HIER`                       AS MVNDR  
  ON DTL.DERIV_MVNDR.MVNDR_NBR = MVNDR.MVNDR_NBR

JOIN `pr-edw-views.SHARED.SKU_HIER_FD`                      AS SKU_HIER
  ON SKU_HIER.SKU_NBR = DTL.SKU_NBR
  AND SKU_HIER.SKU_CRT_DT = DTL.SKU_CRT_DT 

JOIN `pr-edw-views.SHARED.LOC_HIER_FD`                      AS LOCATION
  ON LOCATION.LOC_NBR = SLS.STR_NBR

JOIN `pr-edw-views.SHARED.CAL_PRD_HIER_FD`                  AS CALENDAR
  ON CALENDAR.CAL_DT = SLS_DT

JOIN `pr-edw-views.SLS.STR_COMP_DAY`                        AS COMP
  ON COMP.CAL_DT = CALENDAR.CAL_DT
  AND COMP.STR_NBR = SLS.STR_NBR


WHERE CALENDAR.FSCL_WK_END_DT BETWEEN '2018-01-29' AND '2019-04-07'
AND SLS.SLS_DT BETWEEN '2018-01-29' AND '2019-04-07'
AND POS_TRANS_TYP_CD in ('S', 'R')
AND SKU_HIER.EXT_CLASS_NBR = '025-004'
AND MVNDR.MVNDR_NBR IN (74798, 60002238, 73059, 206820, 76009, 40263, 12879, 76722, 10830, 206823, 87752, 60052261, 70401, 51415, 51414)
AND SKU_HIER.LATEST_SKU_CRT_DT_FLG = TRUE


GROUP BY
 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20

我目前在我的LY_SALESLY_UNITSLY_COMP_SALESLY_COMP_UNITS 列中获得了空值,尽管我知道应该有一些地点在去年同期销售这些商品。我想要得到的是让那些前一年的价值与当年的价值一起出现。任何帮助将不胜感激!

谢谢!

【问题讨论】:

    标签: sql join google-bigquery case union


    【解决方案1】:

    这样的条件永远无法满足:SLS.SLS_DT = DATE_SUB(SLS.SLS_DT, INTERVAL 371 DAY)。仅仅因为 SLS_DT 不等于 SLS_DT-371。

    您可以在 CTE 中预聚合表(将 SLS_DT 添加到 group by 列),然后将 CASE 替换为与预聚合表的连接。瞄准这样的东西:它会变成这样(注意 - 在这种情况下没有 SUM):

    CASE WHEN AGGSLS.SLS_DT = DATE_SUB(SLS.SLS_DT, INTERVAL 371 DAY) 
    THEN (COALESCE(AGGSLS.SUM_EXT_RETL_AMT,0) + 
    COALESCE(AGGSLS.SUM_TOT_GDISC_DTL_AMT,0)) 
    ELSE NULL END
    

    【讨论】:

      【解决方案2】:

      两件事: 1) WHEN 1=1 可以简单地表示为WHEN TRUE,这样可以更容易地移动语句而不会破坏 AND/OR 链接

      2) 获取去年的销售额。您可以从最终查询中省略年份并使用 where 子句限制输出,或者创建一个较小的表,其中包含今年的销售额和去年每周的销售额。

      在我看来,去年的 weeknum 销售是最好的选择,因为您可以在其他地方使用它。但它和你写的很相似

      它看起来像:

      SELECT CALENDAR.FSCL_WK_DESC as week_num,
      sum(case when year = year(current_date()) then (COALESCE(DTL.UNT_SLS,0)) * COMP.STR_COMP_IND else 0 end) as this_year
      sum(case when year = year(current_date())-1 then (COALESCE(DTL.UNT_SLS,0)) * COMP.STR_COMP_IND else 0 end) as last_year 
      
      

      然后您使用week_num 重新加入原始表

      希望对你有用

      干杯!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-26
        • 2021-11-24
        • 1970-01-01
        • 1970-01-01
        • 2022-11-22
        相关资源
        最近更新 更多