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.0dà 1.5mentre datepart(hour, '1900-01-01 09:00:30.000')/2.0dà 4.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.