Cách nhóm thời gian theo giờ hoặc 10 phút


167

như khi tôi làm

SELECT [Date]
  FROM [FRIIB].[dbo].[ArchiveAnalog]
  GROUP BY [Date]

Làm thế nào tôi có thể chỉ định thời gian nhóm?

MS SQL 2008

Chỉnh sửa lần 2

Tôi đang cô

SELECT MIN([Date]) AS RecT, AVG(Value)
  FROM [FRIIB].[dbo].[ArchiveAnalog]
  GROUP BY (DATEPART(MINUTE, [Date]) / 10)
  ORDER BY RecT

đã thay đổi% 10 thành / 10. có thể tạo đầu ra Ngày mà không cần mili giây không?

Câu trả lời:


213

cuối cùng cũng xong

GROUP BY
DATEPART(YEAR, DT.[Date]),
DATEPART(MONTH, DT.[Date]),
DATEPART(DAY, DT.[Date]),
DATEPART(HOUR, DT.[Date]),
(DATEPART(MINUTE, DT.[Date]) / 10)

11
Tôi đã tạo ra nó ROUND((DATEPART(MINUTE, DT.[Date]) / 5),0,1) * 5, để khi tôi nhìn vào dữ liệu, nó tương quan với khe thời gian gần nhất
hdost

7
Năm, tháng và ngày có thể được đơn giản hóa DATE(DT.[Date]).

@Keelan Không hoạt động với tôi - tuy nhiên CHUYỂN ĐỔI (ngày, DT. [Ngày]).
Dan Parsonson

datepart(hour, workingPolicy.workingHours)/2.0cho đi 1.5trong khi datepart(hour, '1900-01-01 09:00:30.000')/2.0cho đi 4.5, tôi không hiểu tại sao? Lưu ý: workPolicy. WorkHours = 1900-01-01 09: 00: 30.000 . vui lòng giúp đỡ
affanBajwa

65

Tôi đến bữa tiệc rất muộn, nhưng điều này không xuất hiện trong bất kỳ câu trả lời hiện có nào:

GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', date_column) / 10 * 10, '2000')
  • Các điều khoản 10MINUTEcó thể được thay đổi thành bất kỳ số nào và DATEPART, tương ứng.
  • Đó là một DATETIMEgiá trị, có nghĩa là:
    • Nó hoạt động tốt trong khoảng thời gian dài. (Không có va chạm giữa các năm.)
    • Bao gồm nó trong SELECTcâu lệnh sẽ cung cấp cho đầu ra của bạn một cột với đầu ra khá bị cắt ở mức bạn chỉ định.
  • '2000'là một "ngày neo" xung quanh việc SQL sẽ thực hiện phép toán ngày. J bdnh đã phát hiện ra bên dưới rằng bạn gặp phải một số nguyên tràn với neo trước đó ( 0) khi bạn nhóm các ngày gần đây theo giây hoặc mili giây.
SELECT   DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', aa.[date]) / 10 * 10, '2000')
                                                               AS [date_truncated],
         COUNT(*) AS [records_in_interval],
         AVG(aa.[value]) AS [average_value]
FROM     [friib].[dbo].[archive_analog] AS aa
GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', aa.[date]) / 10 * 10, '2000')
ORDER BY [date_truncated]

Nếu dữ liệu của bạn kéo dài hàng thế kỷ, sử dụng một ngày neo duy nhất cho nhóm thứ hai hoặc mili giây vẫn sẽ gặp phải tràn. Nếu điều đó đang xảy ra, bạn có thể yêu cầu mỗi hàng neo so sánh việc đóng thùng với nửa đêm của ngày đó:

  • Sử dụng DATEADD(DAY, DATEDIFF(DAY, 0, aa.[date]), 0)thay vì '2000'bất cứ nơi nào nó xuất hiện ở trên. Truy vấn của bạn sẽ hoàn toàn không thể đọc được, nhưng nó sẽ hoạt động.

  • Một sự thay thế có thể CONVERT(DATETIME, CONVERT(DATE, aa.[date]))là sự thay thế.

2 32 ≈ 4,29E + 9, vì vậy nếu DATEPARTlà của bạn SECOND, bạn nhận được 4,3 tỷ giây ở hai bên hoặc "neo ± 136 năm". Tương tự, 2 32 mili giây là .7 49,7 ngày.
Nếu dữ liệu của bạn thực sự nhịp thế kỷ hoặc thiên niên kỷ và là vẫn còn chính xác đến từng giây hoặc millisecond ... xin chúc mừng! Dù bạn đang làm gì, hãy tiếp tục làm nó.


nó sẽ có thể làm điều này từ một ngày bắt đầu cụ thể?
Pylander

1
@pylander Chắc chắn rồi. Chỉ cần đặt một wheremệnh đề trước group by.
Michael - Clay Shirky ở đâu

2
Tôi hiểu rồi. Vì vậy, việc thay đổi điều này / 20 * 20có giống như thu thập dữ liệu trong khoảng thời gian 20 phút không? Xin lỗi, tôi đang vật lộn với toán học ngay bây giờ.
Bỏ qua

2
đối với THỨ HAI là DATEPART, tôi nhận được thông báo lỗi ( The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.). Có vẻ như MINUTE là ngày tháng nhỏ nhất bạn có thể sử dụng với phương pháp này.
jeroenh

1
@jeroenh, bạn đúng rồi. Tôi đã thêm một phần để nói về điều đó. tldr: Thay đổi 0thành '2000'(trích dẫn rất quan trọng!) và thử SECONDlại.
Michael - Clay Shirky ở đâu

17

Trong T-SQL, bạn có thể:

SELECT [Date]
  FROM [FRIIB].[dbo].[ArchiveAnalog]
  GROUP BY [Date], DATEPART(hh, [Date])

hoặc là

theo phút sử dụng DATEPART(mi, [Date])

hoặc là

10 phút sử dụng DATEPART(mi, [Date]) / 10(như Timothy đề xuất)


1
NHÓM THEO [Ngày], DATEPART (hh, [Ngày]) là một mớ hỗn độn, phải không?
cnd

1
@nCdy Nên ổn, nếu không, bạn sẽ gặp lỗi "... không hợp lệ trong danh sách chọn vì nó không có trong hàm tổng hợp hoặc mệnh đề GROUP BY"
tzup 15/211

1
Làm thế nào để bạn nhóm theo cả ngày và theo giờ trong cùng một lúc? Tôi chỉ đang sử dụng Ngày tối thiểu.
cnd

nếu bạn sử dụng Min (Ngày) thì tất nhiên bạn có thể lấy Ngày trong Nhóm theo.
tzup

3
Phút chia cho 10 sẽ tạo nhóm theo khoảng thời gian 10 phút, điều tôi cần. Modulo 10 không có ý nghĩa.
Tar

12

Trong khoảng thời gian 10 phút, bạn sẽ

GROUP BY (DATEPART(MINUTE, [Date]) / 10)

Như đã được đề cập bởi tzup và Pieter888 ... để thực hiện một khoảng thời gian, chỉ cần

GROUP BY DATEPART(HOUR, [Date])

2
nhưng ở đây tôi nhóm các phút của năm 1980 với các phút của năm 2011: SI cần quan tâm đến nó.
cnd

% Sẽ là toán đúng? Điều đó sẽ không tạo ra 10 nhóm. Ví dụ: 1% 10 = 9 2% 10 = 8 Nó thậm chí sẽ không nhất thiết phải là nhóm theo trình tự thời gian chính xác. Tôi nghĩ chỉ cần một sự phân chia bình thường sẽ là chính xác. Trừ khi% không phải là phần còn lại trong sql.
Steven

12
Phút chia cho 10 sẽ tạo nhóm theo khoảng thời gian 10 phút, điều tôi cần. Modulo 10 không có ý nghĩa.
Tar

Đồng ý với Tar. Việc nhóm không có ý nghĩa.
MikeMurko

7

Nên là một cái gì đó như

select timeslot, count(*)  
from 
    (
    select datepart('hh', date) timeslot
    FROM [FRIIB].[dbo].[ArchiveAnalog]  
    ) 
group by timeslot

(Không chắc chắn 100% về cú pháp - Tôi là một loại người của Oracle)

Trong Oracle:

SELECT timeslot, COUNT(*) 
FROM
(  
    SELECT to_char(l_time, 'YYYY-MM-DD hh24') timeslot 
    FROM
    (
        SELECT l_time FROM mytab  
    )  
) GROUP BY timeslot 

6

Câu trả lời ban đầu của tác giả đã cho tác phẩm khá tốt. Chỉ cần mở rộng ý tưởng này, bạn có thể làm một cái gì đó như

group by datediff(minute, 0, [Date])/10

sẽ cho phép bạn nhóm trong một khoảng thời gian dài hơn sau đó 60 phút, ví dụ 720, tức là nửa ngày, v.v.


1
Điều gì sẽ là truy vấn MySQL cho ở trên?
Biranchi

4

Đối với MySql:

GROUP BY
DATE(`your_date_field`),
HOUR(`your_date_field`),
FLOOR( MINUTE(`your_date_field`) / 10);

1

Giải pháp của tôi là sử dụng một hàm để tạo một bảng với các khoảng thời gian và sau đó nối bảng này với dữ liệu tôi muốn nhóm bằng khoảng thời gian trong bảng. Khoảng thời gian sau đó có thể dễ dàng được chọn khi trình bày dữ liệu.

CREATE FUNCTION [dbo].[fn_MinuteIntervals]
    (
      @startDate SMALLDATETIME ,
      @endDate SMALLDATETIME ,
      @interval INT = 1
    )
RETURNS @returnDates TABLE
    (
      [date] SMALLDATETIME PRIMARY KEY NOT NULL
    )
AS
    BEGIN
        DECLARE @counter SMALLDATETIME
        SET @counter = @startDate
        WHILE @counter <= @endDate
            BEGIN
                INSERT INTO @returnDates VALUES ( @counter )
                SET @counter = DATEADD(n, @interval, @counter)
            END
        RETURN
    END

1
declare @interval tinyint
set @interval = 30
select dateadd(minute,(datediff(minute,0,[DateInsert])/@interval)*@interval,0), sum(Value_Transaction)
from Transactions
group by dateadd(minute,(datediff(minute,0,[DateInsert])/@interval)*@interval,0)

8
Chào mừng đến với stackoverflow. Bạn cần phải giải thích đầy đủ câu trả lời của bạn và những gì điều này thêm vào 10 câu trả lời khác đã có trên trang web.
Simon.SA

0

Đối với SQL Server 2012, mặc dù tôi tin rằng nó sẽ hoạt động trong SQL Server 2008R2, tôi sử dụng cách tiếp cận sau đây để giảm thời gian xuống còn mili giây:

DATEADD(MILLISECOND, -DATEDIFF(MILLISECOND, CAST(time AS DATE), time) % @msPerSlice, time)

Điều này hoạt động bởi:

  • Lấy số mili giây giữa một điểm cố định và thời gian đích:
    @ms = DATEDIFF(MILLISECOND, CAST(time AS DATE), time)
  • Lấy phần còn lại của việc chia những mili giây đó thành các lát thời gian:
    @rms = @ms % @msPerSlice
  • Thêm phần âm của phần còn lại vào thời gian đích để lấy thời gian lát:
    DATEADD(MILLISECOND, -@rms, time)

Thật không may, vì điều này tràn ra với micro giây và các đơn vị nhỏ hơn, vì vậy các bộ dữ liệu lớn hơn, tốt hơn sẽ cần sử dụng một điểm cố định ít thuận tiện hơn.

Tôi đã không kiểm tra nghiêm ngặt điều này và tôi không có dữ liệu lớn, vì vậy số dặm của bạn có thể thay đổi, nhưng hiệu suất không đáng kể so với các phương pháp khác đã thử trên thiết bị và bộ dữ liệu của chúng tôi và việc thanh toán thuận tiện cho nhà phát triển để cắt tùy ý cho chúng tôi.


0
select from_unixtime( 600 * ( unix_timestamp( [Date] ) % 600 ) ) AS RecT, avg(Value)
from [FRIIB].[dbo].[ArchiveAnalog]
group by RecT
order by RecT;

thay thế hai 600 bằng bất kỳ số giây nào bạn muốn nhóm.

Nếu bạn cần điều này thường xuyên và bảng không thay đổi, như tên Lưu trữ gợi ý, có thể sẽ nhanh hơn một chút để chuyển đổi và lưu trữ ngày (& thời gian) dưới dạng không thời gian trong bảng.


0

Tôi biết tôi đến trễ chương trình với cái này, nhưng tôi đã sử dụng nó - cách tiếp cận khá đơn giản. Điều này cho phép bạn có được các lát cắt 60 phút mà không có bất kỳ vấn đề làm tròn nào.

Select 
   CONCAT( 
            Format(endtime,'yyyy-MM-dd_HH:'),  
            LEFT(Format(endtime,'mm'),1),
            '0' 
          ) as [Time-Slice]

0
select dateadd(minute, datediff(minute, 0, Date), 0),
       sum(SnapShotValue)
FROM [FRIIB].[dbo].[ArchiveAnalog]
group by dateadd(minute, datediff(minute, 0, Date), 0)

1
Vui lòng cung cấp một số giải thích khi bạn trả lời một câu hỏi.
Shizzen83
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.