Cara mengelompokkan waktu berdasarkan jam atau 10 menit


167

seperti ketika saya melakukannya

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

bagaimana saya bisa menentukan periode grup?

MS SQL 2008

Edit ke-2

Saya mencoba

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

diubah% 10 menjadi / 10. mungkinkah membuat output Date tanpa milidetik?

Jawaban:


213

akhirnya selesai dengan

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

11
Saya membuatnya ROUND((DATEPART(MINUTE, DT.[Date]) / 5),0,1) * 5, sehingga ketika saya melihat data itu berkorelasi dengan slot waktu terdekat
hdost

7
Tahun, bulan, dan hari dapat disederhanakan menjadi DATE(DT.[Date]).

@Keelan Tidak bekerja untuk saya - namun CONVERT (date, DT. [Date]) tidak.
Dan Parsonson

datepart(hour, workingPolicy.workingHours)/2.0memberi 1.5sambil datepart(hour, '1900-01-01 09:00:30.000')/2.0memberi 4.5, saya tidak mengerti mengapa? Catatan: workingPolicy.workingHours = 1900-01-01 09: 00: 30.000 . tolong bantu
affanBajwa

65

Saya sangat terlambat ke pesta, tetapi ini tidak muncul di salah satu jawaban yang ada:

GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', date_column) / 10 * 10, '2000')
  • Ketentuan 10dan MINUTEdapat diubah ke nomor apa saja dan DATEPART, masing-masing.
  • Ini adalah DATETIMEnilai, yang berarti:
    • Ini berfungsi dengan baik di interval waktu yang lama. (Tidak ada tabrakan antara tahun.)
    • Menyertakannya dalam SELECTpernyataan akan memberikan kolom output dengan output cantik terpotong pada tingkat yang Anda tentukan.
  • '2000'adalah "jangkar tanggal" di mana SQL akan melakukan matematika tanggal. Jereonh menemukan di bawah ini bahwa Anda menemukan bilangan bulat bilangan bulat dengan jangkar sebelumnya ( 0) ketika Anda mengelompokkan tanggal terbaru dengan detik atau milidetik.
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]

Jika data Anda membentang berabad-abad, menggunakan tanggal jangkar tunggal untuk pengelompokan detik atau milidetik masih akan menghadapi overflow. Jika itu terjadi, Anda dapat meminta setiap baris untuk mengaitkan perbandingan binning dengan tengah malam tanggalnya sendiri:

  • Gunakan DATEADD(DAY, DATEDIFF(DAY, 0, aa.[date]), 0)alih-alih '2000'dimanapun itu muncul di atas. Permintaan Anda akan benar-benar tidak dapat dibaca, tetapi itu akan berhasil.

  • Alternatif mungkin CONVERT(DATETIME, CONVERT(DATE, aa.[date]))sebagai pengganti.

2 32 ≈ 4.29E + 9, jadi jika Anda DATEPARTyaitu SECOND, Anda mendapatkan 4,3 miliar detik di kedua sisi, atau "anchor ± 136 tahun." Demikian pula, 2 32 milidetik adalah ≈ 49,7 hari.
Jika data Anda benar-benar mencakup berabad-abad atau milenia dan masih akurat hingga detik atau milidetik ... selamat! Apa pun yang Anda lakukan, terus lakukan.


apakah mungkin untuk melakukan ini dari tanggal mulai tertentu?
Pylander

1
@pylander Tentu. Cukup beri whereklausa sebelum group by.
Michael - Di mana Clay Shirky

2
Saya melihat. Jadi, apakah mengubah ini / 20 * 20sama dengan mengumpulkan data untuk interval 20 menit? Maaf, saya sedang berjuang untuk matematika sekarang.
Lopsided

2
untuk SECOND as DATEPART saya mendapatkan pesan kesalahan ( 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.). Tampaknya MINUTE adalah bagian data terkecil yang dapat Anda gunakan dengan pendekatan ini.
jeroenh

1
@ Joenenh, Anda benar. Saya telah menambahkan bagian untuk membicarakan hal itu. tldr: Ubah 0ke '2000'(kutipan itu penting!) dan coba SECONDlagi.
Michael - Di mana Clay Shirky

17

Di T-SQL Anda dapat:

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

atau

dengan penggunaan menit DATEPART(mi, [Date])

atau

dengan 10 menit penggunaan DATEPART(mi, [Date]) / 10(seperti yang disarankan Timothy)


1
KELOMPOK DENGAN [Tanggal], DATEPART (hh, [Tanggal]) berantakan, bukan?
cnd

1
@nCdy Seharusnya baik-baik saja, jika tidak Anda mendapatkan kesalahan "... tidak valid dalam daftar pilih karena tidak terkandung dalam fungsi agregat atau klausa GROUP BY"
tzup

1
Bagaimana Anda mengelompokkan berdasarkan tanggal dan jam secara bersamaan? Saya hanya menggunakan Min Date.
cnd

jika Anda menggunakan Min (Tanggal) maka tentu saja Anda dapat mengeluarkan Tanggal dalam Grup Menurut.
tzup

3
Menit dibagi 10 akan membuat pengelompokan dengan interval 10 menit, yang saya butuhkan. Modulo 10 tidak masuk akal.
Tar

12

Untuk interval 10 menit, Anda akan melakukannya

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

Seperti yang telah disebutkan oleh tzup dan Pieter888 ... untuk melakukan interval satu jam, adil

GROUP BY DATEPART(HOUR, [Date])

2
tetapi di sini saya mengelompokkan risalah 1980 tahun dengan risalah 2011: SI perlu peduli.
cnd

Apakah% matematika yang benar? Bukankah itu membuat 10 grup. Sebagai contoh: 1% 10 = 9 2% 10 = 8 Bahkan pengelompokan kronologis yang benar pun tidak perlu. Saya pikir hanya pembagian normal akan benar. Kecuali% bukan sisa pembagian dalam sql.
Steven

12
Menit dibagi 10 akan membuat pengelompokan dengan interval 10 menit, yang saya butuhkan. Modulo 10 tidak masuk akal.
Tar

Setuju dengan Tar. Pengelompokan tidak masuk akal.
MikeMurko

7

Seharusnya seperti itu

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

(Tidak 100% yakin tentang sintaksisnya - saya lebih seperti tipe orang Oracle)

Di 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

Jawaban asli yang diberikan penulis bekerja dengan sangat baik. Hanya untuk memperluas ide ini, Anda dapat melakukan sesuatu seperti

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

yang akan memungkinkan Anda untuk mengelompokkan dalam jangka waktu lebih lama dari 60 menit, katakan 720, yang setengah hari dll


1
Apa yang akan menjadi permintaan MySQL untuk hal di atas?
Biranchi

4

Untuk MySql:

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

1

Solusi saya adalah menggunakan fungsi untuk membuat tabel dengan interval tanggal dan kemudian bergabung dengan tabel ini ke data yang ingin saya kelompokkan menggunakan interval tanggal dalam tabel. Interval tanggal kemudian dapat dengan mudah dipilih saat menyajikan data.

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
Selamat datang di stackoverflow. Anda harus sepenuhnya menjelaskan jawaban Anda, dan apa yang ini tambahkan ke 10 jawaban lainnya yang sudah ada di situs.
Simon.SA

0

Untuk SQL Server 2012, meskipun saya percaya ini akan bekerja di SQL Server 2008R2, saya menggunakan pendekatan berikut untuk mendapatkan waktu mengiris milidetik:

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

Ini bekerja dengan:

  • Mendapatkan jumlah milidetik antara titik tetap dan waktu target:
    @ms = DATEDIFF(MILLISECOND, CAST(time AS DATE), time)
  • Mengambil sisa membagi milidetik ke dalam irisan waktu:
    @rms = @ms % @msPerSlice
  • Menambahkan sisa negatif itu ke waktu target untuk mendapatkan waktu irisan:
    DATEADD(MILLISECOND, -@rms, time)

Sayangnya, seperti ini meluap dengan mikrodetik dan unit yang lebih kecil, sehingga set data yang lebih besar dan lebih halus perlu menggunakan titik tetap yang kurang nyaman.

Saya belum menentukan dengan seksama hal ini dan saya tidak berada dalam data besar, jadi jarak tempuh Anda dapat bervariasi, tetapi kinerjanya tidak jauh lebih buruk daripada metode lain yang dicoba pada peralatan dan set data kami, dan pembayaran dalam kenyamanan pengembang untuk pemotongan secara sewenang-wenang membuatnya berharga. untuk kita.


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

ganti dua 600 dengan jumlah detik yang Anda inginkan untuk dikelompokkan.

Jika Anda sering membutuhkan ini dan tabelnya tidak berubah, seperti yang disarankan oleh Arsip, mungkin akan sedikit lebih cepat untuk mengonversi dan menyimpan tanggal (& waktu) sebagai waktu tidakix dalam tabel.


0

Saya tahu saya terlambat ke pertunjukan dengan yang ini, tapi saya menggunakan ini - pendekatan yang cukup sederhana. Ini memungkinkan Anda untuk mendapatkan irisan 60 menit tanpa masalah pembulatan.

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
Harap berikan beberapa penjelasan saat Anda menjawab pertanyaan.
Shizzen83
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.