Come raggruppare il tempo per ora o per 10 minuti


167

come quando lo faccio

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

come posso specificare il periodo del gruppo?

MS SQL 2008

2a modifica

sto provando

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

modificato da% 10 a / 10. è possibile effettuare l'output della data senza millisecondi?

Risposte:


213

finalmente finito

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

11
L'ho fatto ROUND((DATEPART(MINUTE, DT.[Date]) / 5),0,1) * 5, in modo che quando guardo i dati sia correlato con la fascia oraria più vicina
hdost

7
Anno, mese e giorno possono essere semplificati DATE(DT.[Date]).

@Keelan Non funziona per me, tuttavia CONVERT (data, DT. [Data]).
Dan Parsonson,

datepart(hour, workingPolicy.workingHours)/2.01.5mentre datepart(hour, '1900-01-01 09:00:30.000')/2.04.5, non capisco perché? Nota: workingPolicy.workingHours = 1900-01-01 09: 00: 30.000 . per favore
aiutatemi

65

Sono in ritardo alla festa, ma questo non appare in nessuna delle risposte esistenti:

GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', date_column) / 10 * 10, '2000')
  • I termini 10e MINUTEpossono essere cambiati in qualsiasi numero e DATEPART, rispettivamente.
  • È un DATETIMEvalore, che significa:
    • Funziona bene su lunghi intervalli di tempo. (Non vi è alcuna collisione tra gli anni.)
    • Includendolo nell'istruzione, il SELECTtuo output sarà una colonna con output piuttosto troncato al livello specificato.
  • '2000'è una "data di ancoraggio" attorno alla quale SQL eseguirà la matematica della data. Jereonh ha scoperto di seguito che si verifica un overflow di numeri interi con l'ancora precedente ( 0) quando si raggruppano le date recenti per secondi o millisecondi.
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]

Se i tuoi dati durano secoli, ‡ l' utilizzo di una singola data di ancoraggio per il raggruppamento di secondi o millisecondi incontrerà comunque l'overflow. Se ciò accade, puoi chiedere a ciascuna riga di ancorare il confronto binning alla mezzanotte della sua data:

  • Usa DATEADD(DAY, DATEDIFF(DAY, 0, aa.[date]), 0)invece di '2000'dove appare sopra. La tua query sarà totalmente illeggibile, ma funzionerà.

  • Un'alternativa potrebbe essere CONVERT(DATETIME, CONVERT(DATE, aa.[date]))la sostituzione.

2 32 ≈ 4.29E + 9, quindi se i vostri DATEPARTa dire SECOND, si ottiene 4,3 miliardi di secondi su entrambi i lati, o "ancora ± 136 anni." Allo stesso modo, 2 32 millisecondi sono ≈ 49,7 giorni.
Se i tuoi dati si estendono in realtà per secoli o millenni ed è ancora accurato al secondo o millisecondo ... congratulazioni! Qualunque cosa tu stia facendo, continua a farlo.


sarebbe possibile farlo da una data di inizio specifica?
Pylander,

1
@pylander Certo. Basta mettere una whereclausola prima del group by.
Michael - Dov'è Clay Shirky il

2
Vedo. Quindi cambiare questo / 20 * 20sarebbe lo stesso della raccolta di dati per intervalli di 20 minuti? Mi dispiace, sto lottando per la matematica in questo momento.
Sbilenco

2
per SECONDO come DATEPART ricevo un messaggio di errore ( 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.). Sembra che MINUTE sia la parte più piccola che puoi usare con questo approccio.
jeroenh,

1
@jeroenh, hai ragione. Ho aggiunto una sezione per parlarne. tldr: cambia 0in '2000'(le virgolette sono importanti!) e riprova SECOND.
Michael - Dov'è Clay Shirky il

17

In T-SQL puoi:

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

o

per minuto DATEPART(mi, [Date])

o

di 10 minuti di utilizzo DATEPART(mi, [Date]) / 10(come suggerito da Timothy)


1
GROUP BY [Date], DATEPART (hh, [Date]) è un casino, no?
cda

1
@nCdy Dovrebbe andare tutto bene, altrimenti verrà visualizzato un errore "... non valido nell'elenco di selezione perché non è contenuto né in una funzione aggregata né nella clausola GROUP BY"
tzup

1
Come si raggruppano per data intera e per ore nello stesso tempo? Sto solo usando la data minima.
cda

se usi Min (Data), ovviamente puoi prendere la Data nel Gruppo per.
martedì

3
I minuti divisi per 10 creeranno il raggruppamento per intervalli di 10 minuti, cosa di cui ho bisogno. Modulo 10 non ha senso.
Tar

12

Per un intervallo di 10 minuti, lo faresti

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

Come è già stato detto da Tzup e Pieter888 ... per fare un intervallo di ora, giusto

GROUP BY DATEPART(HOUR, [Date])

2
ma qui raggruppo i verbali del 1980 con i verbali del 2011: a SI deve interessarsene.
CND

% Sarebbe la matematica corretta? Non creerebbe 10 gruppi. Ad esempio: 1% 10 = 9 2% 10 = 8 Non sarebbe nemmeno necessariamente il corretto raggruppamento cronologico. Penso che solo una divisione normale sarebbe corretta. A meno che% non sia una divisione residua in sql.
Steven,

12
I minuti divisi per 10 creeranno il raggruppamento per intervalli di 10 minuti, cosa di cui ho bisogno. Modulo 10 non ha senso.
Tar

Concordato con Tar. Il raggruppamento non ha senso.
MikeMurko,

7

Dovrebbe essere qualcosa di simile

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

(Non sono sicuro al 100% della sintassi: sono più un tipo Oracle)

In 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

La risposta originale dell'autore ha funzionato abbastanza bene. Solo per estendere questa idea, puoi fare qualcosa del genere

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

che ti permetterà di raggruppare per un periodo più lungo di 60 minuti, diciamo 720, che è mezza giornata ecc.


1
Quale sarebbe la query MySQL per quanto sopra?
Biranchi,

4

Per MySql:

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

1

La mia soluzione è utilizzare una funzione per creare una tabella con gli intervalli di date e quindi unire questa tabella ai dati che voglio raggruppare usando l'intervallo di date nella tabella. L'intervallo di date può quindi essere facilmente selezionato quando si presentano i dati.

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
Benvenuto in StackOverflow. Devi spiegare completamente la tua risposta e cosa si aggiunge alle altre 10 risposte già sul sito.
Simon.SA,

0

Per SQL Server 2012, anche se credo che funzionerebbe in SQL Server 2008R2, utilizzo il seguente approccio per ottenere il tempo di taglio al millisecondo:

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

Questo funziona da:

  • Ottenere il numero di millisecondi tra un punto fisso e il tempo target:
    @ms = DATEDIFF(MILLISECOND, CAST(time AS DATE), time)
  • Prendendo il resto della divisione di quei millisecondi in fasce temporali:
    @rms = @ms % @msPerSlice
  • Aggiungendo il negativo di quel resto al tempo target per ottenere il tempo di taglio:
    DATEADD(MILLISECOND, -@rms, time)

Sfortunatamente, così come questo trabocca di microsecondi e unità più piccole, i set di dati più grandi e più fini dovrebbero utilizzare un punto fisso meno conveniente.

Non l'ho rigorosamente confrontato con questo e non mi trovo nei big data, quindi il tuo chilometraggio può variare, ma le prestazioni non erano notevolmente peggiori rispetto agli altri metodi provati sulle nostre apparecchiature e set di dati e il pagamento in termini di convenienza dello sviluppatore per lo slicing arbitrario lo rende utile per noi.


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

sostituire i due 600 con qualsiasi numero di secondi che si desidera raggruppare.

Se ne hai bisogno spesso e la tabella non cambia, come suggerisce il nome Archivio, probabilmente sarebbe un po 'più veloce convertire e archiviare la data (e l'ora) come un tempo unico nella tabella.


0

So di essere in ritardo allo show con questo, ma ho usato questo approccio piuttosto semplice. Ciò consente di ottenere le sezioni da 60 minuti senza problemi di arrotondamento.

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
Fornisci alcune spiegazioni quando rispondi a una domanda.
Shizzen83,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.