2013-01-18 158 views
1

想要获得每个月的记录计数。但是,几个月没有记录,因此没有行被返回。我怎么能得到那个月的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打,不能得到它的工作。 (

回答

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

+0

还没有听说过sqlfiddle,但始终使用jsfiddle。这只是让我的一天感谢。 – Zippy

+0

除非优化器已经发展到这样做,否则可以通过在加入之前聚合来自mydatatable的每月数字来削减一小部分工作。 –

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 
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年的日期范围,并且只查找该月份范围内的匹配记录。

+0

感谢您使用to_char的提示,sql很好。我需要继续学习,因为我需要一些星期五来弥补我的知识。通常我不会深入研究数据库内容。 – Zippy

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