我正在尝试从MySql返回一个结果集,该结果集按年份和月份分组,并且每隔一年/每月返回一个计数。
这是我开始的地方:
SELECT YEAR(p.pEndDate) AS pYear, MONTHNAME(p.pEndDate) AS pMonth, count(*) AS pNum
FROM projects p
WHERE p.status=3
GROUP BY YEAR(p.pEndDate), MONTH(p.pEndDate)
这个SQL基本上完成了我需要的90%,除非有一个月的计数为零。例如,2009年7月零项目的状态为3,所以我得到了:
2008 November 1
2009 January 2
2009 February 2
2009 March 2
2009 April 1
2009 May 2
2009 June 3
2009 August 2
2009 September 1
2009 October 1
2009 November 2
2009 December 1
2010 January 4
2010 February 1
2010 March 1
2010 April 3
2010 May 3
2010 June 3
2010 July 3
2010 August 3
2010 September 3
2010 October 2
2010 November 2
2010 December 3
2011 January 2
2011 February 1
注意七月不在那里。
所以我开始使用另一个表来强制结果集包含July。所以我创建了一个新表'monthTable'并添加了两列monthID int Primary Key,monthName VARCHAR(3)。
我尝试了很多不同的方法来使用这个表,从右边的JOIN开始等等。没有人能够取得成功的结果,事实上我所做的几乎所有事情都会产生与上面相同的结果集。
非常感谢任何帮助!
答案 0 :(得分:1)
我尝试了很多不同的方法来使用这个[monthTable]表,从右边的JOIN开始等等。没有一个让他们产生了成功的结果,事实上我几乎所做的一切都产生了与上面相同的结果集。
FROM projects p WHERE p.status=3
我的猜测是你正在尝试这样的事情
FROM projects p
RIGHT JOIN monthTable m on <join p to m>
WHERE p.status=3`
问题是WHERE子句将过滤掉任何没有任何p.status值(null)的记录。您需要将此类过滤器移动到JOIN子句,如此
FROM projects p
RIGHT JOIN monthTable m on <join p to m> AND p.status=3`
好奇,但是表格如何就足够了,尤其是monthName只是varchar(3)?
monthID int Primary Key, monthName VARCHAR(3).
尝试改为创建它(一次性)
DROP PROCEDURE IF EXISTS FillMonthsTable;
delimiter //
CREATE PROCEDURE FillMonthsTable()
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
drop table if exists monthsTable;
create table monthsTable (theYear int, theMonth int, monthName varchar(20));
SET @x := date('2000-01-01');
REPEAT
insert into monthsTable (theyear, themonth, monthname) SELECT year(@x), month(@x), monthname(@x);
SET @x := date_add(@x, interval 1 month);
UNTIL @x > date('2030-01-01') END REPEAT;
END//
delimiter ;
CALL FillMonthsTable;
DROP PROCEDURE FillMonthsTable;
然后使用此查询(1-pass对数据进行分组,然后左连接以生成0)
SELECT m.theYear, m.theMonth, IFNULL(t.pNum, 0) theCount
FROM monthsTable m
LEFT JOIN (
SELECT YEAR(p.pEndDate) AS pYear, MONTH(p.pEndDate) AS pMonth, count(*) AS pNum
FROM projects p
WHERE p.status=3
GROUP BY YEAR(p.pEndDate), MONTH(p.pEndDate)
) t on t.pYear = m.theYear and t.pMonth = m.theMonth
ORDER BY m.theYear, m.theMonth
答案 1 :(得分:0)
扩展OMG Ponies声明,您需要一个Numbers或Tally表,其中包含一个整数的顺序列表,涵盖您要查询的所有年份的月份和年份。
Create Table Numbers ( Value int not null Primary Key )
Insert Numbers(Value) Values( 1 )
Insert Numbers(Value) Values( 2 )
...
Insert Numbers(Value) Values( 12 )
...
Insert Numbers(Value) Values( 2000 )
Insert Numbers(Value) Values( 2001 )
...
Insert Numbers(Value) Values( 2011 )
Insert Numbers(Value) Values( 2012 )
这将是一次性插入,表格将保持静态,直到您需要更多月或数年为止。有了它,我们现在将您的Projects表左键加入Numbers表:
Select Years.Value As PYear
, Month_Name( Date_Add('2000-01-01', Interval Months.Value - 1 MONTH) ) As PMonth
, Count( P.NonNullableCol ) As PNum
From Numbers As Months
Cross Join Numbers As Years
Left Join Projects As P
On Year( P.PEnddate ) = Years.Value
And Month( P.PEndDate ) = Months.Value
Where Months.Value Between 1 And 12
And Years.Value Between 2008 And 2011
Group By Years.Value, Months.Value
<强>加成强>
根据评论,我们没有被告知基础数据的性质。但是,如果有问题的值是日期而不是日期和时间,那么更快的方法是Calendar表而不是Numbers表。与Numbers表类似,这是一个包含Projects表中日期时间段的连续日期的静态表。
Create Table Calendar ( DateValue date not null Primary Key )
Insert Calendar( DateValue ) Values( '2000-01-01' )
Insert Calendar( DateValue ) Values( '2000-01-02' )
Insert Calendar( DateValue ) Values( '2000-01-03' )
...
Insert Calendar( DateValue ) Values( '2011-03-01' )
Select Year( C.DateValue ) As PYear
, Month( C.DateValue ) As PMonth
, Count( P.NonNullableCol ) As PNum
From Calendar As C
Left Join Projects As P
On P.PEndDate = C.DateValue
Where C.DateValue Between '2008-11-01' And '2011-02-28'
Group By Year( C.DateValue ), Month( C.DateValue )
答案 2 :(得分:0)
如果你有一个名为nums
的辅助表,其整数从0到9,你可以生成任何类型的完整序列。您的问题不是日期值的计数为空,而是日期值根本不存在。所以说你想要在2004年1月到2006年3月之间的月度计数,你可以使用nums
表创建一个临时日期列表,如下所示:
SELECT DISTINCT ADDDATE('2004-01-01',INTERVAL i.i+j.i+k.i MONTH) AS mydate
FROM nums i JOIN nums j JOIN nums k ORDER BY mydate LIMIT 27;
然后如其他地方所述,您将实际数据加入日期列表ON(年份=年份和月份=月份)。
这是在我自己的表(msds)上完成的类似查询,用于说明:
select year(mydate) theyear, monthname(mydate) themonth, coalesce(c,0) thecount
from
(select DISTINCT adddate('2004-01-01',INTERVAL i.i+j.i+k.i MONTH) as mydate
FROM ints i JOIN ints j join ints k ORDER BY mydate LIMIT 27) datelist
left join
(SELECT year(issue_date) as y, month(issue_date) as m, count(*) c FROM msds m where issue_date between '2004-01-01' and '2006-03-01'
group by y, m) mydata
on (year(mydate)=y and month(mydate)=m)