2009-05-06 3 views
3

Ich habe Benutzer-Login-Daten mit Zeitstempeln und was ich tun möchte, ist ein Histogramm von Logins nach Jahr, aber mit dem Jahr beginnend an einem beliebigen Datum. Zum Beispiel möchte ich die folgende Art von Informationen:SQL Server Nicht-Standard-Datum basierte Histogramm

1 May 2005 - 30 Apr 2006 | 525 
1 May 2006 - 30 Apr 2007 | 673 
1 May 2007 - 30 Apr 2008 | 892 
1 May 2006 - 30 Apr 2009 | 1047 

Die Etiketten in der ersten Spalte sind nicht wichtig, aber die Datumsbereiche sind. Ich weiß, ich kann es brechen durch Straße Jahren mit:

SELECT YEAR([date]) AS [year], COUNT(*) AS cnt 
FROM logins 
GROUP BY YEAR([date]) 
ORDER BY [year] 

Aber das gibt mir nicht die Datenbereiche ich will. Wie kann das gemacht werden?

Antwort

3
declare @baseDate datetime 
set @baseDate = '1 May 2005' 

SELECT 
    datediff(year, @baseDate, [date]) AS YearBucket 
    ,COUNT(*) AS cnt 
FROM logins 
GROUP BY datediff(year, @baseDate, [date]) 
ORDER BY datediff(year, @baseDate, [date]) 

EDIT - Entschuldigungen, sind Sie richtig. Hier ist eine feste Version ist

create table logins (date datetime, foo int) 
insert logins values ('1 may 2005', 1) 
insert logins values ('1 apr 2006', 2) 
insert logins values ('1 may 2006', 3) 

declare @baseDate datetime 
set @baseDate = '1 May 2005' 

SELECT 
    datediff(day, @baseDate, [date])/365 AS YearBucket 
    ,COUNT(*) AS cnt 
FROM logins 
GROUP BY datediff(day, @baseDate, [date])/365 
ORDER BY datediff(day, @baseDate, [date])/365 

ändern die datediff Einheiten (Ich sollte eine Testtabelle beginnen ... verwendet), wenn Sie als Tage mehr Granularität wollen.

EDIT # 2 - ok, hier ist eine robustere Lösung, die Schaltjahre behandelt :) EDIT # 3 - Eigentlich geht das nicht mit Schaltjahren, sondern es können variable Zeitintervalle angegeben werden. Gehen Sie mit dateadd (Jahr, 1, @baseDate) für das sichere Schaltjahr.

declare @baseDate datetime, @interval datetime 
[email protected] is expressed as time above 0 time (1/1/1900) 
select @baseDate = '1 May 2005', @interval = '1901' 

declare @timeRanges table (beginIntervalInclusive datetime, endIntervalExclusive datetime) 
declare @i int 
set @i = 1 
while @i <= 10 
begin 
    insert @timeRanges values(@baseDate, @baseDate + @interval) 
    set @baseDate = @baseDate + @interval 
    set @i = @i + 1 
end 

SELECT 
    tr.beginIntervalInclusive, 
    tr.endIntervalExclusive, 
    COUNT(*) AS cnt 
FROM logins join @timeRanges as tr 
    on logins.date >= tr.beginIntervalInclusive 
     and logins.date < tr.endIntervalExclusive 
GROUP BY tr.beginIntervalInclusive, tr.endIntervalExclusive 
ORDER BY tr.beginIntervalInclusive 
+0

Gibt die exakt gleichen Ergebnisse, nur ohne das Jahr davor. – cdeszaq

+0

@cdeszaq - Sie haben Recht, tut mir leid. Abfrage ist jetzt behoben, ich hätte eine Testtabelle verwenden sollen, um damit zu beginnen. – ahains

+0

:) Ich war gerade selbst dazu gekommen ... aber wird es Schaltjahre richtig behandeln, oder wird das Off-by-1-Fehler einführen? – cdeszaq

1

Wenn Sie eine Möglichkeit finden können, Ihre Zeiträume in einer separaten Tabelle zu definieren, dann wählen Sie eine Bezeichnung und zwei Datumsspalten aus und verknüpfen Sie Ihre Hauptanfrage abhängig von Ihren Tabellen.

Select Count(*) as NoLogons, DateRangeLabel 
From logins a 
inner join 
(
Select 
DateRangeLabel, StartDate, EndDate 
From tblMyDates 
) b 
on a.date between b.startdate and b.enddate 
Group by DateRangeLabel