Nhóm theo từng phút và hai phút


8

Tôi có một cột datetime và tôi có thể dễ dàng chạy các truy vấn với một nhóm bằng cột datetime của tôi. Tuy nhiên, tôi muốn chạy các truy vấn nhóm cho

  • Khoảng thời gian 1 phút
  • Khoảng thời gian 2 phút
  • Khoảng thời gian 5 phút
  • Cách nhau 1 giờ
  • Vân vân.

Làm thế nào để tôi làm điều này?


1
Tất cả trong cùng một truy vấn, hoặc bạn muốn truy vấn được nhóm một cách có điều kiện theo một khoảng thời gian xác định? Nếu trước đây, bạn có thể hiển thị dữ liệu mẫu và kết quả mong muốn?
Aaron Bertrand

Mỗi nhóm theo khoảng sẽ có trong một truy vấn khác nhau. Tôi chỉ chọn những khoảng đó làm ví dụ. Ý tưởng là tôi có thể chạy lại truy vấn và dễ dàng điều chỉnh một số mệnh đề để có được 2 phút, 2 phút, 5 phút, v.v.
dublintech

1
Có một cái nhìn vào câu trả lời này. dba.stackexchange.com/questions/17669/ Ấn
Mikael Eriksson

Câu trả lời:


8

Đầ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.)


Cảm ơn những người đứng đầu về GO <int> - Tôi thậm chí không biết đó là một tùy chọn cho GO. Tôi sẽ thêm nó vào danh sách các cải tiến cho SQL Fiddle (trang web của tôi).
Jake Feasel

2
declare @T table
(
  Value datetime
);

insert into @T values ('2012-01-01T00:02:00');
insert into @T values ('2012-01-01T00:03:00');
insert into @T values ('2012-01-01T00:04:00');
insert into @T values ('2012-01-01T00:05:00');
insert into @T values ('2012-01-01T00:06:00');
insert into @T values ('2012-01-01T00:07:00');
insert into @T values ('2012-01-01T00:08:00');
insert into @T values ('2012-01-01T00:09:00');
insert into @T values ('2012-01-01T00:10:00');
insert into @T values ('2012-01-01T00:11:00');

-- Interval in minutes    
declare @Interval int
set @Interval = 4

select count(*) as "Count",
       dateadd(minute, (datediff(minute, 0, Value) / @Interval) * @Interval, 0) as "Value"
from @T
group by dateadd(minute, (datediff(minute, 0, Value) / @Interval) * @Interval, 0);

Kết quả:

Count       Value
----------- -----------------------
2           2012-01-01 00:00:00.000
4           2012-01-01 00:04:00.000
4           2012-01-01 00:08:00.000

0

DATEPARTtrả về số nguyên ...

SELECT
    (DATEPART(MINUTE, StartDate) / 5) * 5, COUNT(*)
FROM
    Table
GROUP BY
    (DATEPART(MINUTE, StartDate) / 5) * 5
ORDER BY
    (DATEPART(MINUTE, StartDate) / 5) * 5

Các số được hiển thị là bắt đầu của thời gian năm phút. Vì vậy, hàng có nhãn "30" bao gồm các sự kiện xảy ra tại X: 30, X: 31, X: 32, X: 33 và X: 34.


Tại sao bạn nhân và chia cho 5. Họ có triệt tiêu lẫn nhau không?
dublintech

1
Có, nhưng vì nó không bảo toàn phân số, kết quả thực là làm tròn xuống bội số gần nhất của năm.
Jon của tất cả các giao dịch

2
Không phải nhóm này cùng nhau trong nhiều giờ? 4:30sẽ được kết hợp với 5:306:30vì phút là như nhau trên bảng. Bạn cần bao gồm ngày và giờ tối thiểu.
JNK

Nếu đó là một phần trong mục tiêu của OP, thì chắc chắn là có. Truy vấn này đáp ứng tiêu chí "truy vấn nhóm trong khoảng thời gian X phút". Mở rộng khi cần thiết.
Jon của tất cả các giao dịch

Chắc chắn, nếu mệnh đề where giới hạn tất cả dữ liệu trong vòng một giờ, nó sẽ đáp ứng các tiêu chí. Tôi không nghĩ rằng đủ rõ ràng trong câu hỏi hoặc câu trả lời của bạn. IMHO.
Aaron Bertrand
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.