2012-04-04 15 views
0

Ich habe folgenden Satz von Daten:keine Aufzeichnungen für bestimmten Monat in SQL COUNT und GROUP BY Monat

ID | CREATED  | USER 
-------------------------- 
1 | 2012-01-14 | XYZ 
2 | 2012-03-14 | XYZ 
3 | 2012-03-15 | XYZ 
4 | 2012-03-24 | ABC 
5 | 2012-04-10 | XYZ 
6 | 2012-04-11 | ABC 

Und ich brauche einen Bericht, der die COUNT für einen bestimmten Benutzer zeigt, sondern auch einen mit 0 für Monate wo es keine Aufzeichnungen gibt.

Ich schaffte es zu arbeiten, aber ohne die 0 seit Monaten ohne Aufzeichnungen. Bis jetzt habe ich diese Syntax, die einen Fehler wirft.

SELECT Month(CREATED), COUNT(SELECT * FROM SEARCHES WHERE USER = 'XYZ') 
FROM SEARCHES 
GROUP BY Month(CREATED) 

Antwort

1

Hier werden allgemeine Abfrage für die Gruppierung nach Datumsbereich ist. @startDate und @endDate definieren den Bereich; Sie können min (erstellt) und max (erstellt) für den Benutzer oder einen festen Bereich festlegen.

CTE monthlyRange generiert Tabelle der Monate - zuerst des aktuellen Monats, zuerst des nächsten Monats. Die Suche wird später linksbündig zu monthlyRanges erstellt. Beachten Sie, dass der Benutzer in Join gefiltert wird, da dieser Join links ist und das Filtern in Where-Klausel ihn effektiv in Inner Join umwandelt.

declare @startDate datetime 
declare @endDate datetime 
set @startDate = '2012-01-01' 
set @endDate = '2013-01-01' 

; with monthlyRange (startMonth, startNextMonth) as (
    select dateadd (m, datediff (m, 0, @startDate), 0), 
     dateadd (m, datediff (m, 0, @startDate) + 1, 0) 
    union all 
    select dateadd (m, 1, startMonth), 
     dateadd (m, 1, startNextMonth) 
    from monthlyRange 
    where startNextMonth <= dateadd (m, datediff (m, 0, @endDate), 0) 
) 
SELECT Year(monthlyRange.startMonth) Year, 
     Month(monthlyRange.startMonth) Month, 
     COUNT(searches.Created) Count 
    FROM monthlyRange 
    left join SEARCHES 
    on monthlyRange.startMonth <= Searches.Created 
    and monthlyRange.startNextMonth > Searches.Created 
    and [USER] = 'XYZ' 
GROUP BY Year(monthlyRange.startMonth), Month(monthlyRange.startMonth) 
order by 1, 2 

Here is Sql Fiddle for testing

+0

Das funktionierte großartig! Danke auch für die Einführung in SQL Giddle. – greener

2

Sie können nicht nach Daten suchen, die nicht dort sind. Sie müssen also der Tabelle beitreten, die alle Monate, an denen Sie teilnehmen möchten, entweder auflistet (oder Liste simuliert). Wie das geht, hängt von den verwendeten rdbms ab. Es ist üblich, rownum zu verwenden, um eine Liste zu erstellen, die in Monate konvertiert werden kann. Oder Postgres hat eine Funktion, um eine Serie zu generieren. Nebenbei verstehe ich nicht wirklich, warum die Unterauswahl in der Spaltenklausel ist, anstatt den Filter zur Hauptabfrage hinzuzufügen. auch

Siehe:

SQL frequency distribution query to count ranges with group-by and include 0 counts

How to generate list of all dates between sysdate-30 and sysdate+30?

0

Try this:

CREATE TABLE #DaTable(
    ID INT, 
    CREATED DATE, 
    USER_ VARCHAR(10) 
) 
INSERT INTO #DaTable(ID, CREATED, USER_) VALUES 
(1 , '2012-01-14', 'XYZ'), 
(2 , '2012-03-14' , 'XYZ'), 
(3 , '2012-03-15' , 'XYZ'), 
(4 , '2012-03-24' , 'ABC'), 
(5 , '2012-04-10' , 'XYZ'), 
(6 , '2012-04-11' , 'ABC') 

CREATE TABLE #DaMonths(
    Nr INT, 
    Name VARCHAR(10) 
) 
INSERT INTO #DaMonths(Nr, Name) VALUES 
(1, 'Jan'), 
(2, 'Feb'), 
(3, 'Mar'), 
(4, 'Apr'), 
(5, 'May'), 
(6, 'Jun'), 
(7, 'Jul'), 
(8, 'Aug'), 
(9, 'Sep'), 
(10, 'Oct'), 
(11, 'Nov'), 
(12, 'Dec') 

SELECT M.Nr, M.Name, COUNT(DT.ID) as Count_ 
FROM #DaMonths as M 
    LEFT OUTER JOIN #DaTable as DT ON 
    M.Nr = Month(DT.CREATED) 
GROUP BY M.Nr, M.Name 
ORDER BY M.Nr