月份分组 - 计算每个月的数量

时间:2013-01-18 17:14:33

标签: sql oracle oracle10g

希望获得每个月的记录数。但是,几个月没有记录,因此没有返回行。那个月如何计算0?

select months, count(rowid) as counter from (
    select  to_char(date_entered, 'MM') as months
    from mydatatable
    where to_char(date_entered, 'yyyy') = '2011'
     )
group by months
order by months

结果:

Month    Count
01       32
03       12
04       11
06       10
07       222
08       32

甚至尝试使用subq select 1,2,3,4,5,6,7,8,9,10,11,12 from dual并且无法使其工作。还没有枢轴功能...;(

4 个答案:

答案 0 :(得分:2)

你可能最好在表格中存储01到12,但一般方法是使用左连接:

Select
  m.Mo,
  Count(t.dateentered)
From (
    Select '01' As Mo From Dual Union All
    Select '02' From Dual Union All
    Select '03' From Dual Union All
    Select '04' From Dual Union All
    Select '05' From Dual Union All
    Select '06' From Dual Union All
    Select '07' From Dual Union All
    Select '08' From Dual Union All
    Select '09' From Dual Union All
    Select '10' From Dual Union All
    Select '11' From Dual Union All
    Select '12' From Dual
  ) m
    Left Outer Join
  mydatatable t
    On
      m.Mo = to_char(t.dateentered, 'MM') And 
      t.dateentered >= DATE'2011-01-01' And
      t.dateentered < DATE'2012-01-01'
Group By
  m.Mo
Order By
  m.Mo

更新使用了一种更加指数友好的限制年份的方式。

http://sqlfiddle.com/#!4/68085/10

答案 1 :(得分:1)

您需要构建自己的12行月“表”并执行左外连接。从您的问题中获取查询,并使其成为内联视图以提供数据。

SELECT m.month "Month", nvl(md.data, 0) "Count"
FROM
(
   select '01' month from dual union all
   select '02' month from dual union all
   select '03' month from dual union all
   select '04' month from dual union all
   select '05' month from dual union all
   select '06' month from dual union all
   select '07' month from dual union all
   select '08' month from dual union all
   select '09' month from dual union all
   select '10' month from dual union all
   select '11' month from dual union all
   select '12' month from dual
) m LEFT OUTER JOIN (
   /* Your Query Here */
) md ON m.month = md.month
ORDER BY m.month;

结果应该是这样的:

Month       Count
------ ----------
01             32
02              0
03             12
04             11
05              0
06             10
07            222
08             32
09              0
10              0
11              0
12              0

答案 2 :(得分:0)

您可以使用connect by syntax of a hierarchical query构建包含月份数字的虚拟表格,然后左键加入您的数据:

with months as (
    select to_char(level, 'FM00') as month
    from dual
    connect by level <= 12
)
select m.month,
    count(mdt.rowid) as counter
from months m
left join mydatatable mdt
    on mdt.date_entered >= to_date('01/' || m.month || '/2011', 'DD/MM/YYYY')
    and mdt.date_entered <
        add_months(to_date('01/' || m.month || '/2011', 'DD/MM/YYYY'), 1)
group by m.month
order by m.month;

有一些补充数据:

create table mydatatable (date_entered date, dummy number);
insert into mydatatable values (date '2011-06-02', 0);
insert into mydatatable values (date '2011-07-01', 0);
insert into mydatatable values (date '2011-10-01', 0);
insert into mydatatable values (date '2011-10-31', 0);
insert into mydatatable values (date '2011-11-01', 0);

......这给了:

MONTH COUNTER
----- -------
01          0 
02          0 
03          0 
04          0 
05          0 
06          1 
07          1 
08          0 
09          0 
10          2 
11          1 
12          0 

SQL Fiddle因为这似乎是最近要做的事情......


通常最好避免使用to_char(date_entered, 'yyyy') = '2011'之类的内容,因为您将to_char()函数应用于表中的每一行,如果该列上有索引,则不会使用它。而是尝试转换过滤器以匹配列的数据类型,例如date_entered > date '2011-01-01' and date_entered < date '2012-01-01'。在这种情况下,无论如何都可以在连接条件中处理 - 我将每个月转换为2011年的日期范围,并且仅查找该月范围内的匹配记录。

答案 3 :(得分:0)

这很奇怪......也许我误解了问题或数据......?在您的问题中添加表格和数据始终是个好主意。您应该获得所有月份的所有数据。我试过这个:

SELECT * FROM stack_test
/
CURR_MONTH  VAL
---------------
01          10
02          15
03          20
04  
05  

正如您所看到的,第4个月和第5个月没有值:

 SELECT months, COUNT(rowid) counter 
   FROM
    (
     SELECT curr_month months
       FROM stack_test
    )
 GROUP BY months
 ORDER BY months
 /
 MONTHS COUNTER
 -------------------
 01           1
 02           1
 03           1
 04           1
 05           1

另一个例子:第2个月没有任何价值,但我仍然可以理解。也许你需要总结你的价值......:

SELECT mth, SUM(val) total_sum, Count(*) total_cnt 
  FROM 
  (
  SELECT mth, (CASE WHEN Mth = '01' THEN '10' ELSE '0' END) val
    FROM
    ( -- Annual table - replace 2 with 12 in Add_Months for the whole year -- 
     SELECT Trunc(SYSDATE,'Y')+Level-1 Curr_Year_By_Date
        , To_char(Trunc(SYSDATE, 'MM') + Rownum-1, 'MM' ) Mth
     FROM dual
    CONNECT BY Level <= Add_Months(Trunc(SYSDATE,'Y'),2)-Trunc(SYSDATE,'Y')
   )
  )
 GROUP BY mth
 ORDER BY 1
 /
 MTH    TOTAL_SUM   TOTAL_CNT
 -------------------------------------
 01         310         31
 02         0           28