当Oracle中特定星期没有数据时,如何将值填充为零

时间:2018-11-14 10:08:35

标签: sql oracle plsql

我有一个具有以下结构的表。

Note_title varchar2(100)
Note_created_on date

现在在报告中,我想显示每周创建的所有笔记,因此我为它实施了以下解决方案。

SELECT to_char(Note_created_on - 7/24,'ww')||'/'||to_char(Note_created_on - 7/24,'yyyy') as Week ,
nvl(COUNT(Note_title),'0') as AMOUNT
FROM Notes
GROUP BY to_char(Note_created_on - 7/24,'ww') ,
to_char(Note_created_on -7/24,'yyyy')
ORDER BY to_char(Note_created_on - 7/24,'ww') DESC

我从中得到正确的输出,但是假设第42,45周没有创建任何注释,那么它只是缺少它。 样本输出:

WEEK    AMOUNT
46/2018 3
44/2018 22
43/2018 45
41/2018 1
40/2018 2
39/2018 27
38/2018 23

那么我如何在第42,45周获得零值而不是将它们排除在外?

3 个答案:

答案 0 :(得分:0)

正如jarlh所述:

创建星期列表:

SELECT TO_CHAR(LEVEL, 'FM00')||'/2018' wk
FROM dual
CONNECT BY LEVEL <= 53

此查询生成53行,级别仅是一个数字.... 2 ..最多53。我们将其格式化为01/2018,02/2018 .. 53/2018

如果您打算在其他年份使用此查询,最好将年份设置为动态:

SELECT TO_CHAR(LEVEL, 'FM00')||TO_CHAR(sysdate-7/24,'/YYYY') wk
FROM dual
CONNECT BY LEVEL <= 53

(感谢Barbaros指出,Oracle将任何一年的最后一天报告为在第53周,或者说是7 * 52 = 364)

我们将注释数据加入其中。我不清楚您为什么要从日期中减去7个小时(时区?),但我还是留下了。我消除了计数的复杂性,因为您似乎只想要特定一周中的记录计数。我还删除了双精度to_char,因为您可以在单个操作中完成所有操作。不需要TO_CHAR(date, 'WW')||'/'||TO_CHAR(date,'YYYY')等。您只需使用WW/YYYY作为格式即可。现在,我们的查询如下:

SELECT lst.wk as week, COALESCE(amt, 0) as amount FROM
(
  SELECT TO_CHAR(LEVEL, 'FM00')||TO_CHAR(sysdate-7/24,'/YYYY') wk
  FROM dual
  CONNECT BY LEVEL <= 52
) lst
LEFT OUTER JOIN
(
  SELECT 
    to_char(Note_created_on - 7/24,'ww/yyyy') as wk,
    COUNT(*) as amt
  FROM Notes
  GROUP BY to_char(Note_created_on - 7/24,'ww/yyyy') 
) dat
ON lst.wk = dat.wk
ORDER BY lst.wk

在没有音符的星期中,左连接在该星期中记录为空,因此我们将其合并为0。

您当然可以用其他方式(许多方式)进行查询,这是一个比较:

SELECT lst.wk as week,  COUNT(dat.wk) as amount FROM
(
  SELECT TO_CHAR(LEVEL, 'FM00')||TO_CHAR(sysdate-7/24,'/YYYY') wk
  FROM dual
  CONNECT BY LEVEL <= 52
) lst
LEFT OUTER JOIN
(
  SELECT 
    to_char(Note_created_on - 7/24,'ww/yyyy') as wk
  FROM Notes
) dat
ON lst.wk = dat.wk
GROUP BY lst.wk
ORDER BY lst.wk

在这种形式下,我们在加入后进行groupby / count。通过计算dat.wk(对于某些lst.wk可能为NULL),我们可以省略合并,因为count(null)为0

答案 1 :(得分:0)

首先,您需要生成每年之间的所有星期,之后再与“ Notes”表上的“周”合并,然后按“生成的周”分组。例如:

 with weeks
        as ( select level as lvl /*Assume 52 weeks in a calendar year..*/
               from dual 
             connect by level <=52
            )
     ,weeks_year
       as (select distinct 
                  b.lvl||'/'||trunc(Note_created_on,'YYYY') as week_year_val /*From the start of year in Note_created_on*/
            from Notes a
            join weeks b
               on 1=1      
           )
  SELECT a.week_year_val as Week 
         ,COUNT(Note_title) as AMOUNT
     FROM weeks_year a
LEFT JOIN Notes b
       ON a.week_year_val=to_char(b.Note_created_on - 7/24,'ww')||'/'||to_char(b.Note_created_on - 7/24,'yyyy')
GROUP BY a.week_year_val
ORDER BY a.week_year_val DESC

答案 2 :(得分:0)

如果要在当前年份的 中执行此操作,则可以使用以下 SQL语句,该语句使用如下的RIGHT JOIN

SELECT d.week as Week,
       nvl(COUNT(Note_title), '0') as AMOUNT
  FROM Notes
 RIGHT JOIN 
(SELECT lpad(level,2,'0')|| '/' ||to_char(sysdate,'yyyy') as week, 
        '0' as amount FROM dual CONNECT BY level <= 53) d
    ON 
      ( d.week = 
 to_char(Note_created_on - 7 / 24, 'ww') ||'/'||to_char(Note_created_on - 7 / 24, 'yyyy') )
 GROUP BY d.week
 ORDER BY d.week DESC;

P.S。人们普遍认为,一年由52组成,是正确的但被截断了:)。因此,我使用了53

请注意,select to_char( date'2016-12-31' - 7 / 24, 'ww') from dual将产生53作为样本。

Rextester Demo