3

YEAR と MONTH でグループ化され、YEAR/MONTH ごとにカウントが返される 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

7 月がそこにないことに注意してください。

そこで、別のテーブルを使用して、結果セットに 7 月を強制的に含める調査を開始しました。そこで、新しいテーブル「monthTable」を作成し、2 つの列 monthID int Primary Key、monthName VARCHAR(3) を追加しました。

RIGHT JOINなどから始めて、このテーブルを使用するさまざまな方法を試しました..成功した結果が得られたものはありません.実際、私が行うほとんどすべてで、上記と同じ結果セットが得られます.

どんな助けでも大歓迎です!

4

3 に答える 3

1

I've tried many different ways of using this [monthTable] table, starting with a RIGHT JOIN and so on.. none have them have yielded successful results, in fact almost everything I do yields the same result set as above.

FROM projects p WHERE p.status=3

My guess is that you were trying something like this

FROM projects p
RIGHT JOIN monthTable m on <join p to m>
WHERE p.status=3`

The problem is that the WHERE clause will be filtering out any record that doesn't have any p.status values (null). You need to move such filters to the JOIN clause, like this

FROM projects p
RIGHT JOIN monthTable m on <join p to m> AND p.status=3`

Curious, but how does a table like suffice, esp with monthName being only varchar(3)?

monthID int Primary Key, monthName VARCHAR(3).

Try creating it like this instead (one-off)

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;

Then using this query (1-pass to group your data, then a left join to produce the 0s)

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
于 2011-03-01T18:39:27.230 に答える
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 )

これは 1 回限りの挿入であり、さらに数か月または数年が必要になるまで、テーブルは静的なままです。これで、Projects テーブルを Numbers テーブルに Left Join します。

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

添加

コメントによると、基礎となるデータの性質については知らされていません。ただし、問題の値が日付と時刻ではなく日付である場合は、Numbers テーブルではなく、Calendar テーブルを使用する方が高速です。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 )
于 2011-03-01T18:23:31.850 に答える
0

nums0 から 9 までの整数で呼び出される補助テーブルがある場合、任意のタイプの切れ目のないシーケンスを生成できます。あなたの問題は、日付値のカウントがnullであることではなく、日付値がまったく存在しないことです。たとえば、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)
于 2011-03-01T18:29:30.220 に答える