Đầu tiên, một bảng và một số dữ liệu mẫu để chơi với:
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
(Tôi sẽ làm điều này trong sqlfiddle nhưng tôi không chắc nó hỗ trợ GO <int>có nhiều hàng và nó bị kẹt trên INSERT> 8000 ký tự.)
Bây giờ một thủ tục được lưu trữ:
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
Và một số cách sử dụng mẫu:
EXEC dbo.GetGroupedIntervals @MinuteInterval = 1;
EXEC dbo.GetGroupedIntervals @MinuteInterval = 2;
EXEC dbo.GetGroupedIntervals @MinuteInterval = 5;
Để cho ngắn gọn, tôi sẽ hiển thị kết quả cho cuộc gọi cuối cùng, nhưng bạn có thể chơi với những người khác.
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
Một số lưu ý:
- Phép nối sử dụng s.dt có khả năng thực hiện tốt hơn bất kỳ phương thức trích xuất nào sử dụng datepart nếu cột datetime trong bảng cơ sở của bạn có một chỉ mục (hoặc có thể trong tương lai).
- Tôi giả sử bạn muốn hiển thị tất cả các khoảng trong phạm vi. Nếu bạn không muốn hiển thị các khoảng với 0 đếm, chỉ cần thay đổi liên kết ngoài bên trái thành tham gia bên trong.
- Tôi đi xuống một phút trong trường hợp ngày bắt đầu được làm tròn khi được chuyển đổi thành SMALLDATETIME. Trong khoảng thời gian 1 phút và có thể là những khoảng thời gian khác, điều này có thể dẫn đến 0 lần đếm cho khoảng thời gian đầu tiên. Bạn có thể điều chỉnh cách làm tròn số này xảy ra (ví dụ: bạn có thể sử dụng FLOOR () để đảm bảo nó luôn làm tròn). Tất cả phụ thuộc vào mức độ chính xác mà bạn cần phải có.
- Tôi không bao gồm bất kỳ mệnh đề WHERE nào nhưng bạn có thể cần phải có những điều khoản để lọc. Ví dụ: truy vấn của bạn có thể muốn tất cả các khoảng thời gian cho một ngày nhất định. Bạn có thể muốn thay đổi cách tính
datesđể tạo ra tất cả các khoảng thời gian trong ngày, thay vì tất cả các khoảng thời gian giữa thời gian tối thiểu và tối đa được tìm thấy trong dbo.SomeTablengày đó. Biến thể sau đây xử lý vấn đề này, bằng cách trình bày dữ liệu cho một ngày bắt đầu từ nửa đêm và tăng dần theo @MinutInterval:
...
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
Cuộc gọi mẫu:
EXEC dbo.GetGroupedIntervalsByDay @Date = '20120516', @MinuteInterval = 1;
EXEC dbo.GetGroupedIntervalsByDay @Date = '20120516', @MinuteInterval = 2;
EXEC dbo.GetGroupedIntervalsByDay @Date = '20120516', @MinuteInterval = 5;
Kết quả rút gọn từ cuộc gọi cuối cùng:
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
. sẽ để lại trường hợp đó như một bài tập cho người đọc.)