2012-03-22 7 views
9

sto cercando di gruppo alcuni record in intervalli da 5, 15, 30 e 60 minuti:Gruppo DateTime in 5,15,30 e 60 intervalli di un minuto

SELECT AVG(value) as "AvgValue", 
sample_date/(5*60) as "TimeFive" 
FROM DATA 
WHERE id = 123 AND sample_date >= 3/21/2012 

voglio correre diverse query , ognuno raggrupperebbe i miei valori medi negli incrementi di tempo desiderati. Quindi la query di 5 minuti sarebbe tornato risultati come questo:

AvgValue TimeFive 
6.90  1995-01-01 00:05:00 
7.15  1995-01-01 00:10:00 
8.25  1995-01-01 00:15:00 

La query 30 minuti si tradurrebbe in questo:

AvgValue TimeThirty 
6.95  1995-01-01 00:30:00 
7.40  1995-01-01 01:00:00 

La colonna datetime è in yyyy-mm-dd hh:mm:ss formato

io sono sempre errori di conversione impliciti nella colonna datetime. Ogni aiuto è molto apprezzato!

+0

Non è ovvio per me cosa intendi per "raggruppamento in intervalli diversi". Ricordando che i risultati sono necessariamente righe in colonne, puoi mostrare quali saranno le righe di esempio dei tuoi dati? In particolare, non mi è chiaro, un id sarà in un gruppo di 1 5 minuti, anche in un gruppo di 15 minuti, anche in un gruppo di 30 minuti ... ecc. Se ogni record sarà in 4 gruppi, ad esempio, quali sono i nomi delle colonne che vuoi nel risultato? –

+2

Inoltre, se hai intenzione di pubblicare un numero di domande sql, 1) tagga sempre la domanda con il tipo specifico di server (vedo dal titolo che è MS SQL, ma se hai usato i tag che ti suggeriscono che puoi specificare una versione) e 2) puoi abbassare il "costo di capire che cosa significa la domanda" prendendo il tempo per impostare un sql fiddle (http://sqlfiddle.org); ti permette di inserire esempi di dati che vuoi interrogare. –

+1

Solo per chiarire qualcosa: 'DATETIME' in SQL Server è ** mai ** memorizzato in un formato basato su stringhe - è memorizzato internamente come due valori INT a 4-byte. Questo formato potrebbe essere la tua ** presentazione predefinita ** - ma è ** NON ** memorizzato in quel formato! –

risposta

15

Utilizzando

datediff(minute, '1990-01-01T00:00:00', yourDatetime) 

vi darà il numero di minuti dal 1990/01/01 (è possibile utilizzare la data base desiderata).

Quindi è possibile dividere per 5, 15, 30 o 60 e raggruppare in base al risultato di questa divisione. L'ho risarcito sarà valutato come una divisione intera, quindi otterrai un numero intero che puoi utilizzare per raggruppare.

cioè

group by datediff(minute, '1990-01-01T00:00:00', yourDatetime) /5 

UPDATE Poiché la domanda iniziale è stato modificato per richiedere i dati da visualizzare in formato data-ora dopo il raggruppamento, ho aggiunto questa semplice query che farà quello che l'OP vuole:

-- This convert the period to date-time format 
SELECT 
    -- note the 5, the "minute", and the starting point to convert the 
    -- period back to original time 
    DATEADD(minute, AP.FiveMinutesPeriod * 5, '2010-01-01T00:00:00') AS Period, 
    AP.AvgValue 
FROM 
    -- this groups by the period and gets the average 
    (SELECT 
     P.FiveMinutesPeriod, 
     AVG(P.Value) AS AvgValue 
    FROM 
     -- This calculates the period (five minutes in this instance) 
     (SELECT 
      -- note the division by 5 and the "minute" to build the 5 minute periods 
      -- the '2010-01-01T00:00:00' is the starting point for the periods 
      datediff(minute, '2010-01-01T00:00:00', T.Time)/5 AS FiveMinutesPeriod, 
      T.Value 
     FROM Test T) AS P 
    GROUP BY P.FiveMinutesPeriod) AP 

NOTA: ho diviso questo in 3 sottointerrogazioni per chiarezza. Dovresti leggerlo dall'interno. Potrebbe, ovviamente, essere scritto come una singola query compatta

NOTA: se si modifica il periodo e la data di inizio, è possibile ottenere qualsiasi intervallo necessario, ad esempio settimane a partire da un determinato giorno, o tutto ciò che può essere necessario

Se si desidera generare dati di test per questa query utilizzare questo:

CREATE TABLE Test 
(Id INT IDENTITY PRIMARY KEY, 
Time DATETIME, 
Value FLOAT) 

INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:00:22', 10) 
INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:03:22', 10) 
INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:04:45', 10) 
INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:07:21', 20) 
INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:10:25', 30) 
INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:11:22', 30) 
INSERT INTO Test(Time, Value) VALUES('2012-03-22T00:14:47', 30) 

il risultato della esecuzione della query è questo:

Period      AvgValue 
2012-03-22 00:00:00.000 10 
2012-03-22 00:05:00.000 20 
2012-03-22 00:10:00.000 30 
.515.053.691,36321 milioni
+1

Suggerisco '19900101' piuttosto che' 1990-1-1', poiché il formato tratteggiato per specificare date senza orari è ambiguo. (Naturalmente, va bene in questo esempio specifico, ma se il mese e il giorno sono diversi, SQL Server può interpretarlo in uno dei due modi, o aumentare un errore di conversione) –

+0

Grazie per il consiglio. Ho eseguito questa query e sembrava raggruppare i miei valori medi in righe nei risultati, ma non sono in grado di ottenere il valore di tempo aggregato da visualizzare nei risultati della query. Ho modificato il tuo post per descrivere il mio tentativo di visualizzare la colonna temporale nei risultati della query – jrubengb

+0

Ho provato a utilizzare il formato "19900101" come descritto da Damien_The_Unbeliever e sembra funzionare, tuttavia non ho notato differenze nell'iniziale risultati delle query. Grazie per il suggerimento. – jrubengb

4

Quindi, nel caso in cui si Googled questo, ma è necessario farlo in mysql, che è stato il mio caso:

In MySQL si può fare

GROUP BY 
CONCAT(
    DATE_FORMAT(`timestamp`,'%m-%d-%Y %H:'), 
    FLOOR(DATE_FORMAT(`timestamp`,'%i')/5)*5 
) 
+1

... ma la domanda riguarda SQL Server, non il mio SQL ?! – Tanner

+4

La domanda riguarda 'sql-server', ma è anche etichettata con' sql', quindi includerebbe tutti gli aromi – chiliNUT

3

Sulla @ risposta di Jotabe (a cui ho non posso commentare altrimenti sarei in grado di provare qualcosa di simile che non richiederebbe una subquery.

SELECT 
    AVG(value) AS 'AvgValue', 

    -- Add the rounded seconds back onto epoch to get rounded time 
    DATEADD(
     MINUTE, 
     (DATEDIFF(MINUTE, '1990-01-01T00:00:00', your_date)/30) * 30, 
     '1990-01-01T00:00:00' 
    )  AS 'TimeThirty' 

FROM YourTable 
-- WHERE your_date > some max lookback period 
GROUP BY 
    (DATEDIFF(MINUTE, '1990-01-01T00:00:00', your_date)/30) 

Questa modifica rimuove le tabelle temporanee e le sottoquery.Utilizza la stessa logica di base per il raggruppamento di intervalli di 30 minuti ma, quando si presentano i dati come parte del risultato, sto solo invertendo il calcolo dell'intervallo per ottenere la data arrotondata &.

Problemi correlati