Saati saate veya 10 dakikaya göre gruplama


167

yaptığım gibi

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

grup dönemini nasıl belirleyebilirim?

MS SQL 2008

2. Düzenleme

deniyorum

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

% 10 / / 10 olarak değiştirildi. Tarih çıktısını milisaniye olmadan yapmak mümkün mü?

Yanıtlar:


214

sonunda bitti

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

11
Bunu yaptım ROUND((DATEPART(MINUTE, DT.[Date]) / 5),0,1) * 5, böylece verilere baktığımda en yakın zaman
dilimiyle

7
Yıl, ay ve gün basitleştirilebilir DATE(DT.[Date]).

@Keelan Benim için çalışmıyor - ancak CONVERT (tarih, DT. [Tarih]) çalışıyor.
Dan Parsonson

datepart(hour, workingPolicy.workingHours)/2.0verir 1.5iken datepart(hour, '1900-01-01 09:00:30.000')/2.0verir 4.5, ben niye anlamıyorsun? Not: workingPolicy.workingHours = 1900-01-01 09: 00: 30.000 . lütfen yardım
affanBajwa

65

Partiye çok geç kaldım, ancak bu mevcut cevapların hiçbirinde görünmüyor:

GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', date_column) / 10 * 10, '2000')
  • 10Ve MINUTEterimleri herhangi bir sayı olarak değiştirildi ve edilebilmektedir DATEPARTsırasıyla.
  • Bu bir DATETIMEdeğerdir, yani:
    • Uzun zaman aralıklarında iyi çalışır. (Yıllar arasında bir çarpışma yoktur.)
    • İfadeye dahil edilmesi, SELECTçıktınıza, belirttiğiniz düzeyde kesilmiş güzel bir çıktı içeren bir sütun verecektir.
  • '2000'SQL'in tarih matematiğini gerçekleştireceği bir "çapa tarihi" dir. Jereonh , son tarihleri ​​saniye veya milisaniye göre grupladığınızda , önceki çapa ( ) ile tamsayı taşmasıyla karşılaştığınızı aşağıda keşfetti0 .
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]

Verileriniz yüzyıllara yayılıyorsa, ikinci veya milisaniye gruplama için tek bir bağlantı tarihi kullanmak yine de taşma ile karşılaşacaktır. Bu durumda, her satırdan binning karşılaştırmasını kendi tarihinin gece yarısına sabitlemesini isteyebilirsiniz:

  • Yukarıda göründüğü yer DATEADD(DAY, DATEDIFF(DAY, 0, aa.[date]), 0)yerine kullanın '2000'. Sorgunuz tamamen okunamayacak, ancak işe yarayacak.

  • Bunun CONVERT(DATETIME, CONVERT(DATE, aa.[date]))yerine bir alternatif de olabilir .

2 32 ≈ 4.29E + 9, bu nedenle eğer DATEPARTIS SECOND, sen iki tarafında 4300000000 saniye olsun, ya da "çapa ± 136 yıl." Benzer şekilde, 2 32 milisaniye ≈ 49.7 gündür.
Eğer gerçekte açıklıklı yüzyıllar veya bin sene öncesine ve bir veri hala saniye veya milisaniye ... tebrikler doğru! Ne yaparsan yap, yapmaya devam et.


bunu belirli bir başlangıç ​​tarihinden itibaren yapmak mümkün müdür?
Pylander

1
@pylander Tabii. Sadece bir wherecümle koy group by.
Michael - Clay Shirky

2
Anlıyorum. Peki, bunu / 20 * 2020 dakikalık aralıklarla veri toplamakla değiştirmek mi gerekir? Üzgünüm, şu anda matematikte mücadele ediyorum.
Lopsided

2
DATEPART olarak SECOND için bir hata mesajı alıyorum ( 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.). MINUTE, bu yaklaşımla kullanabileceğiniz en küçük tarih bölümü gibi görünüyor.
jeroenh

1
@jeroenh, haklısın. Bunun hakkında konuşmak için bir bölüm ekledim. TLDR: Değişim 0için '2000'(tırnak önemlidir!) ve deneyin SECONDtekrar.
Michael - Clay Shirky

17

T-SQL'de şunları yapabilirsiniz:

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

veya

dakika kullanım DATEPART(mi, [Date])

veya

10 dakikalık kullanım DATEPART(mi, [Date]) / 10(Timothy'nin önerdiği gibi)


1
GROUP BY [Tarih], DATEPART (ss, [Tarih]) karışıklık değil mi?
cnd

1
@nCdy İyi olmalı, aksi takdirde "... toplama işlevinde veya GROUP BY deyiminde bulunmadığından seçim listesinde geçersiz" hatası alırsınız
tzup

1
Tüm tarihe ve saatlere göre aynı zamanda nasıl gruplandırıyorsunuz? Sadece Min Date kullanıyorum.
cnd

Min (Tarih) kullanıyorsanız, tabii ki Gruplama Tarihindeki Tarihi çıkarabilirsiniz.
tzup

3
10'a bölünen dakikalar, 10 dakikalık aralıklarla gruplama oluşturur, bu da neye ihtiyaç duyduğudur. Modulo 10 bir anlam ifade etmiyor.
Tar

12

10 dakikalık bir aralık için

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

Tzup ve Pieter888 tarafından daha önce de belirtildiği gibi ... bir saat aralığı yapmak için

GROUP BY DATEPART(HOUR, [Date])

2
ama burada 1980 yılının dakikalarını 2011'in dakikalarıyla gruplandırıyorum: SI bunu önemsemeli.
cnd

% Doğru matematik olur mu? Bu 10 grup oluşturmaz. Örneğin:% 1 10 = 9 2% 10 = 8 Doğru kronolojik gruplandırma da olması gerekmez. Bence normal bir ayrım doğru olur. % Sql'de kalan bir bölünme olmadığı sürece.
Steven

12
10'a bölünen dakikalar, 10 dakikalık aralıklarla gruplama oluşturur, bu da neye ihtiyaç duyduğudur. Modulo 10 bir anlam ifade etmiyor.
Tar

Tar ile aynı fikirde. Gruplama mantıklı değil.
MikeMurko

7

Gibi bir şey olmalı

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

(Sözdiziminden% 100 emin değilim - ben daha çok Oracle tipi biriyim)

Oracle'da:

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

6

Yazarın verdiği orijinal cevap oldukça iyi çalışıyor. Sadece bu fikri genişletmek için,

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

Bu, 60 dakikadan uzun bir süre gruplandırmanıza olanak tanır, örneğin 720, yarım gün vb.


1
Yukarıdakiler için MySQL sorgusu ne olur?
Biranchi

4

MySql için:

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

1

Benim çözüm tarih aralıklarla bir tablo oluşturmak için bir işlev kullanmak ve sonra bu tabloyu tablodaki tarih aralığını kullanarak gruplamak istediğiniz veriye katılmaktır. Tarih aralığı daha sonra veriler sunulurken kolayca seçilebilir.

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
Stackoverflow'a hoş geldiniz. Cevabınızı ve bunun sitedeki diğer 10 cevaba ne kattığını tam olarak açıklamanız gerekir.
Simon.SA

0

SQL Server 2012 için SQL Server 2008R2'de çalışacağına inandığım halde, milisaniyeye kadar dilimleme yapmak için aşağıdaki yaklaşımı kullanıyorum:

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

Bu şu şekilde çalışır:

  • Sabit bir nokta ile hedef zaman arasındaki milisaniye sayısını alma:
    @ms = DATEDIFF(MILLISECOND, CAST(time AS DATE), time)
  • Bu milisaniyelerin zaman dilimlerine bölünmesinin geri kalanını almak:
    @rms = @ms % @msPerSlice
  • Dilim süresini elde etmek için kalan sürenin negatifini hedef süreye eklemek:
    DATEADD(MILLISECOND, -@rms, time)

Ne yazık ki, bu mikrosaniye ve daha küçük birimlerle taşması gibi, daha büyük, daha ince veri kümelerinin daha az uygun bir sabit nokta kullanması gerekecektir.

Bunu titizlikle karşılaştırmadım ve büyük verilerde değilim, bu nedenle kilometreniz değişebilir, ancak performans, ekipmanlarımızda ve veri setlerimizde denenen diğer yöntemlerden belirgin şekilde daha kötü değildi ve geliştiricinin keyfi dilimleme için sağladığı kolaylık bunu değerli kılıyor bizim için.


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

iki 600'ü gruplandırmak istediğiniz herhangi bir saniye ile değiştirin.

Buna sık sık ihtiyacınız varsa ve Arşiv'in adından da anlaşılacağı gibi, tablo değişmezse, tarihi (& saati) tablodaki bir unixtime olarak dönüştürmek ve depolamak muhtemelen biraz daha hızlı olacaktır.


0

Bu gösteriye geç kaldığımı biliyorum, ama bunu kullandım - oldukça basit bir yaklaşım. Bu, 60 dakikalık dilimleri yuvarlama sorunu yaşamadan almanızı sağlar.

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
Bir soruyu cevaplarken lütfen bazı açıklamalar sağlayın.
Shizzen83
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.