Oracle SQL - 过去12个月按月分组,填补数据空白

时间:2017-09-18 21:31:22

标签: sql oracle

我看到过与此类似的帖子数量,但没有一个非常适合我正在使用的场景。尝试查询数据库并汇总过去每个月的结果12.如果特定月份没有结果,我希望该特定月份连续0。

运行此查询会生成2016年11月至2017年3月的数据,之前/之后没有结果:

SELECT SUM(PRICE) SumPrice, COUNT(*) TotalNum, EXTRACT(MONTH FROM SALE_DATE) Mo, EXTRACT(YEAR FROM SALE_DATE) Yr
FROM SALES_HIST
WHERE SALE_DATE BETWEEN TRUNC(ADD_MONTHS((LAST_DAY(SYSDATE)+1),-12)) 
AND LAST_DAY(SYSDATE)
AND ITEMNO = 'ABCD'
GROUP BY EXTRACT(MONTH FROM SALE_DATE), EXTRACT(YEAR FROM SALE_DATE)
ORDER BY Yr, Mo;

经过一番搜索后,我想出了这个查询,以便生成过去12个月的列表:

SELECT
EXTRACT(MONTH FROM 
ADD_MONTHS(TRUNC(ADD_MONTHS((LAST_DAY(SYSDATE)+1),-12)), LEVEL - 1)) calMo,
EXTRACT(YEAR FROM 
ADD_MONTHS(TRUNC(ADD_MONTHS((LAST_DAY(SYSDATE)+1),-12)), LEVEL - 1)) calYr
FROM DUAL
CONNECT BY LEVEL <= 12;

我相信我应该能够在我的查询中使用它作为临时表来填补数据空白。这就是我一直在修补的:

WITH cal AS (
SELECT
  EXTRACT(MONTH FROM ADD_MONTHS(TRUNC(ADD_MONTHS((LAST_DAY(SYSDATE)+1),-12)), LEVEL - 1)) calMo,
  EXTRACT(YEAR FROM ADD_MONTHS(TRUNC(ADD_MONTHS((LAST_DAY(SYSDATE)+1),-12)), LEVEL - 1)) calYr
FROM DUAL
CONNECT BY LEVEL <= 12
)
select cal.calMo, cal.calYr, NVL(count(*), 0)
from cal
left join SALES_HIST sh on cal.calMo = EXTRACT(MONTH FROM sh.SALE_DATE)
WHERE SALE_DATE BETWEEN TRUNC(ADD_MONTHS((LAST_DAY(SYSDATE)+1),-12)) AND LAST_DAY(SYSDATE)
AND ITEMNO = 'ABCD'
group by cal.calMo, cal.calYr
order by cal.calYr, cal.calMo;

但这似乎返回与初始查询相同的结果。我假设我错过了加入的东西,但不确定。任何帮助将不胜感激。谢谢!

1 个答案:

答案 0 :(得分:0)

当您使用WHERE子句时,它会过滤掉WHERE子句中条件未满足的LEFT JOIN的所有结果行,因此将删除所有NULL值。如果在sales_hist表的条件中使用AND,它将在创建与cal表中的月/年不匹配的NULL值之前首先过滤这些记录。另外,在计数上使用sh.itemno而不是*,因为它将计算cal表中每个月有1的条目。

SELECT cal.calmo, 
       cal.calyr, 
       NVL(COUNT(sh.itemno), 0) /*changed from * to sh.itemno*/
  FROM cal
  LEFT JOIN sales_hist sh 
    ON cal.calMo = EXTRACT(MONTH FROM sh.sale_date)
   AND sale_date BETWEEN TRUNC(ADD_MONTHS((LAST_DAY(SYSDATE)+1),-12))
                     AND LAST_DAY(SYSDATE) /*changed from WHERE to AND*/
   AND itemno = 'ABCD'
 GROUP BY cal.calmo, 
          cal.calyr
 ORDER BY cal.calyr, 
          cal.calmo;

示例数据

CREATE TABLE sales_hist AS
SELECT TO_DATE('09172017','MMDDYYYY') sale_date,
       'ABCD' itemno
  FROM dual
 UNION ALL
SELECT TO_DATE('10172016','MMDDYYYY') sale_date,
       'ABCD' itemno
  FROM dual
 UNION ALL
SELECT TO_DATE('10182016','MMDDYYYY') sale_date,
       'ABCD' itemno
  FROM dual
   UNION ALL
SELECT TO_DATE('09172016','MMDDYYYY') sale_date,
       'ABCD' itemno
  FROM dual
 ;

示例结果。请注意,09172016不包括在计数中。

CALMO   CALYR   NVL(COUNT(SH.ITEMNO),0)
10      2016    2
11      2016    0
12      2016    0
1       2017    0
2       2017    0
3       2017    0
4       2017    0
5       2017    0
6       2017    0
7       2017    0
8       2017    0
9       2017    1