Zunächst eine Tabelle und einige Beispieldaten zum Spielen:
USE tempdb;
GO
CREATE TABLE dbo.SomeTable(dt DATETIME);
GO
SET NOCOUNT ON;
GO
INSERT dbo.SomeTable(dt) SELECT DATEADD(MINUTE, -22, GETDATE());
GO 45
INSERT dbo.SomeTable(dt) SELECT DATEADD(MINUTE, -19, GETDATE());
GO 32
INSERT dbo.SomeTable(dt) SELECT DATEADD(MINUTE, -17, GETDATE());
GO 21
INSERT dbo.SomeTable(dt) SELECT DATEADD(MINUTE, -12, GETDATE());
GO 16
INSERT dbo.SomeTable(dt) SELECT DATEADD(MINUTE, -5, GETDATE());
GO 55
INSERT dbo.SomeTable(dt) SELECT DATEADD(MINUTE, -2, GETDATE());
GO 26
INSERT dbo.SomeTable(dt) SELECT DATEADD(MINUTE, -1, GETDATE());
GO 71
INSERT dbo.SomeTable(dt) SELECT GETDATE();
GO 14
(Ich würde dies in sqlfiddle tun, aber ich bin nicht sicher, ob es GO <int>
viele Zeilen unterstützt und INSERT
> 8000 Zeichen verschluckt .)
Nun eine gespeicherte Prozedur:
CREATE PROCEDURE dbo.GetGroupedIntervals
@MinuteInterval TINYINT = 1
AS
BEGIN
SET NOCOUNT ON;
DECLARE
@IntervalCount INT, @StartDate SMALLDATETIME;
SELECT
@StartDate = DATEADD(MINUTE, -1, MIN(dt)),
@IntervalCount = (DATEDIFF(MINUTE, MIN(dt), MAX(dt))
+ @MinuteInterval) / @MinuteInterval
FROM dbo.SomeTable -- WHERE ...;
;WITH dates(s,e) AS
(
SELECT
DATEADD(MINUTE, @MinuteInterval*(n.n-1), @StartDate),
DATEADD(MINUTE, @MinuteInterval*(n.n), @StartDate)
FROM
(
SELECT
TOP (@IntervalCount) ROW_NUMBER() OVER (ORDER BY o.[object_id])
FROM sys.all_objects AS o CROSS JOIN sys.all_columns AS c
ORDER BY o.[object_id]
) AS n(n)
)
SELECT StartDate = d.s, c = COUNT(s.dt)
FROM dates AS d
LEFT OUTER JOIN dbo.SomeTable AS s
ON s.dt >= d.s AND s.dt < d.e
-- AND any filter criteria for dbo.SomeTable?
GROUP BY d.s
ORDER BY d.s;
END
GO
Und einige Beispiele für die Verwendung:
EXEC dbo.GetGroupedIntervals @MinuteInterval = 1;
EXEC dbo.GetGroupedIntervals @MinuteInterval = 2;
EXEC dbo.GetGroupedIntervals @MinuteInterval = 5;
Der Kürze halber zeige ich die Ergebnisse für den letzten Anruf, aber Sie können mit den anderen spielen.
StartDate c
------------------- ----
2012-05-16 12:51:00 77
2012-05-16 12:56:00 21
2012-05-16 13:01:00 16
2012-05-16 13:06:00 55
2012-05-16 13:11:00 111
Einige Notizen:
- Der Join mit s.dt ist wahrscheinlich leistungsfähiger als alle Extraktionsmethoden mit datepart, wenn die datetime-Spalte in Ihrer Basistabelle einen Index hat (oder möglicherweise in Zukunft).
- Ich nahm an, Sie wollten alle Intervalle innerhalb des Bereichs anzeigen. Wenn Sie die Intervalle nicht mit 0 anzeigen möchten, ändern Sie einfach die linke äußere Verknüpfung in eine innere Verknüpfung.
- Ich gehe eine Minute runter, falls das Startdatum bei der Konvertierung in SMALLDATETIME aufgerundet wurde. Für das 1-Minuten-Intervall und möglicherweise für andere kann dies zu 0 Zählungen für das erste Intervall führen. Sie können einstellen, wie diese Rundung erfolgt (z. B. können Sie FLOOR () verwenden, um sicherzustellen, dass sie immer abgerundet wird). Alles hängt davon ab, wie genau Sie sein müssen.
- Ich habe keine WHERE-Klausel eingefügt, aber möglicherweise müssen Sie diese zum Filtern haben. Beispielsweise möchte Ihre Abfrage möglicherweise alle Intervalle für einen bestimmten Tag. Möglicherweise möchten Sie die Berechnung von ändern
dates
, um alle Intervalle für den Tag und nicht alle Intervalle zwischen der minimalen und der maximalen Zeit dbo.SomeTable
an diesem Tag zu erstellen . Die folgende Variante sorgt dafür, dass die Daten für einen einzelnen Tag ab Mitternacht angezeigt und um @MinutInterval erhöht werden:
...
CREATE PROCEDURE dbo.GetGroupedIntervalsByDay
@Date DATE,
@MinuteInterval TINYINT = 1
AS
BEGIN
SET NOCOUNT ON;
DECLARE
@IntervalCount INT,
@StartDate SMALLDATETIME = @Date;
SELECT
@IntervalCount = 1440 / @MinuteInterval;
;WITH dates(s,e) AS
(
SELECT
DATEADD(MINUTE, @MinuteInterval*(n.n-1), @StartDate),
DATEADD(MINUTE, @MinuteInterval*(n.n), @StartDate)
FROM
(
SELECT
TOP (@IntervalCount) ROW_NUMBER() OVER (ORDER BY o.[object_id])
FROM sys.all_columns AS o
ORDER BY o.[object_id]
) AS n(n)
)
SELECT StartDate = d.s, c = COUNT(s.dt)
FROM dates AS d
LEFT OUTER JOIN dbo.SomeTable AS s
ON s.dt >= d.s AND s.dt < d.e
-- AND any filter criteria for dbo.SomeTable?
GROUP BY d.s
ORDER BY d.s;
END
GO
Beispielanrufe:
EXEC dbo.GetGroupedIntervalsByDay @Date = '20120516', @MinuteInterval = 1;
EXEC dbo.GetGroupedIntervalsByDay @Date = '20120516', @MinuteInterval = 2;
EXEC dbo.GetGroupedIntervalsByDay @Date = '20120516', @MinuteInterval = 5;
Verkürzte Ergebnisse des letzten Anrufs:
StartDate c
------------------- ----
2012-05-16 00:00:00 0
2012-05-16 00:05:00 0
2012-05-16 00:10:00 0
...
2012-05-16 12:40:00 0
2012-05-16 12:45:00 0
2012-05-16 12:50:00 45
2012-05-16 12:55:00 53
2012-05-16 13:00:00 16
2012-05-16 13:05:00 55
2012-05-16 13:10:00 111
2012-05-16 13:15:00 0
2012-05-16 13:20:00 0
...
2012-05-16 23:45:00 0
2012-05-16 23:50:00 0
2012-05-16 23:55:00 0
(Wenn Sie die Intervalle nicht ohne Zählung einschließen möchten, ändern Sie die linke äußere Verknüpfung in eine innere Verknüpfung. Sie können auch seltsame Ergebnisse erzielen, wenn Sie ein Intervall auswählen, das nicht gut in 1440 passt. I ' Überlasse diesen Fall dem Leser als Übung.)