2012-03-22 10 views
9

Próbuję grupy niektóre zapisy na język odstępach 5-, 15-, 30- i 60-minutowych:Grupa DateTime w 5,15,30 i 60 minutowych odstępach

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

chcę uruchomić kilka zapytań , każdy zgrupuje moje średnie wartości w pożądanych przyrostach czasu. Tak kwerenda 5-min wróci wyniki tak:

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 

30-min zapytania spowodowałoby to:

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

Kolumna datetime jest w formacie

jestem coraz yyyy-mm-dd hh:mm:ss niejawne błędy konwersji w mojej kolumnie datetime. Każda pomoc jest doceniana!

+0

Nie jest dla mnie oczywiste, co rozumiesz przez "zgrupowanie w różnych odstępach czasu". Przypominając, że wyniki są koniecznie wierszami w kolumnach, czy możesz pokazać, jak będą wyglądały przykładowe wiersze Twoich danych? W szczególności nie jest dla mnie jasne, czy jeden id będzie w 1 5-minutowej grupie, także w jednej 15-minutowej grupie, także w jednej 30-minutowej grupie ... itd. Jeśli na przykład każdy rekord będzie w 4 grupach, jakie są nazwy kolumn, które chcesz uzyskać w wyniku? –

+2

Jeśli masz zamiar opublikować kilka pytań sql, 1) zawsze taguj pytanie określonym typem serwera (widzę z tytułu, że jest to MS SQL, ale jeśli używałeś tagów, które sugerują ci że możesz podać wersję) i 2) możesz obniżyć "koszt ustalania, co to pytanie oznacza", poświęcając czas na skonfigurowanie skrzypka sql (http://sqlfiddle.org); pozwala umieścić w przykładach dane, które chcesz przesłać. –

+1

Po prostu wyczyścić coś: 'DATETIME' w SQL Server jest ** nigdy ** przechowywany w formacie opartym na łańcuchach - jest przechowywany jako dwie 4-bajtowe wartości INT wewnętrznie. Ten format może być twoją ** domyślną prezentacją ** - ale jest ** NIE ** przechowywany w tym formacie! –

Odpowiedz

15

Korzystanie

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

daje liczbę minut od 01.01.1990 (można użyć żądaną datę bazową).

Następnie można podzielić przez 5, 15, 30 lub 60 i pogrupować według wyniku tego podziału. Załatałem, że zostanie ono ocenione jako dzielenie całkowite, więc otrzymasz liczbę całkowitą, której możesz użyć do grupowania według.

tj

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

UPDATE jak oryginalne pytanie był edytowany wymagać dane mają być wyświetlane w formacie daty i czasu po zgrupowania, Dodałem tę prostą kwerendę, która będzie robić to, co OP chce:

-- 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 

UWAGA: mam ten podzielony na 3 podzapytania dla jasności. Powinieneś przeczytać to od środka. Można go oczywiście napisać jako pojedyncze, kompaktowe zapytanie: UWAGA: jeśli zmienisz okres i początkową datę-czas, możesz uzyskać dowolny przedział czasowy, np. Tygodnie zaczynające się od danego dnia, lub cokolwiek może trzeba

Jeśli chcesz wygenerować dane testowe dla tego zapytania użyj:

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) 

efektem wykonania zapytania jest następująca:

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 
+1

Proponuję '19900101' zamiast' 1990-1-1', ponieważ format przerywany do określania dat bez czasów jest niejednoznaczny. (Oczywiście w tym konkretnym przykładzie jest to w porządku, ale jeśli miesiąc i dzień są różne, SQL Server może zinterpretować je na jeden z dwóch sposobów lub zgłosić błąd konwersji) –

+0

Dzięki za radę. Uruchomiłem to zapytanie i zdawało mi się, że moje średnie wartości zostały pogrupowane w wiersze w wynikach, ale nie jestem w stanie uzyskać łącznej wartości czasu, która pojawiłaby się w wynikach zapytania. Zmodyfikowałem twój post, aby opisać moją próbę uzyskania kolumny czasu, aby pojawiła się w wynikach zapytania. – jrubengb

+0

Próbowałem używać formatu "19900101" opisanego przez Damien_The_Unbeliever, ale wygląda na to, że działa, jednak nie zauważyłem żadnych różnic w początkowym wyniki zapytania. Dzieki za sugestie. – jrubengb

4

Tak więc, w przypadku google, ale trzeba to zrobić w MySQL, który był moim przypadku:

W MySQL można zrobić

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

... ale pytanie dotyczy serwera sql, a nie mojego sql ?! – Tanner

+4

Pytanie dotyczy 'sql-server', ale jest również oznaczone prostym' sql', więc zawierałoby wszystkie smaki – chiliNUT

3

Opierając się na @ odpowiedź JotaBe za (do którego nie mogę komentować - inaczej bym), możesz też wypróbować coś takiego, co nie wymagałoby podkwerendy.

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) 

Ta zmiana usuwa tabele tymczasowe i podkwerendy.Używa tej samej logiki rdzeniowej do grupowania w odstępach 30-minutowych, ale gdy przedstawiam dane z powrotem jako część wyniku, po prostu odwracam obliczenia interwału, aby uzyskać zaokrągloną datę & czasu.