2009-05-18 22 views
5

ho bisogno di fare qualcosa di simile:Come si calcola una media mobile utilizzando MySQL?

SELECT value_column1 
FROM table1 
WHERE datetime_column1 >= '2009-01-01 00:00:00' 
ORDER BY datetime_column1; 

Tranne in aggiunta a value_column1, ho anche bisogno di recuperare un moving average dei precedenti 20 valori di value_column1.

SQL standard è preferibile, ma userò le estensioni MySQL se necessario.

risposta

18

Questo è appena fuori dalla mia testa, e sto uscendo dalla porta, quindi non è stato testato. Inoltre non riesco a immaginare che possa funzionare molto bene su qualsiasi tipo di set di dati di grandi dimensioni. Ho confermato che funziona almeno senza errori. :)

SELECT 
    value_column1, 
    (
    SELECT 
      AVG(value_column1) AS moving_average 
    FROM 
      Table1 T2 
    WHERE 
      (
       SELECT 
        COUNT(*) 
       FROM 
        Table1 T3 
       WHERE 
        date_column1 BETWEEN T2.date_column1 AND T1.date_column1 
     ) BETWEEN 1 AND 20 
    ) 
FROM 
    Table1 T1 
1

Quando ho avuto un problema simile, ho finito per usare tabelle temporanee per una serie di motivi, ma ci ha fatto questo molto più facile! Quello che ho fatto sembra molto simile a quello che stai facendo, per quanto riguarda lo schema.

Rende lo schema qualcosa come ID identità, start_date, end_date, valore. Quando si seleziona, eseguire una selezione secondaria dei 20 precedenti in base all'ID identità.

Eseguire questa operazione solo se si trovano già le tabelle temporanee per altri motivi (ho colpito le stesse righe più e più volte per metriche diverse, quindi è stato utile avere il set di dati di piccole dimensioni).

+0

Non sono sicuro di dove entrino i tavoli temporanei, posso usare la tua soluzione senza di loro. Anche se, ha il problema di fare affidamento sulla colonna di identità che è contigua. –

+0

La colonna di identità è contigua è un po 'l'intero punto della tabella temporanea ... Nel mio caso, ho anni e anni di dati, ma ogni mese di dati viene elaborato da solo. Estraggo i dati nelle tabelle temporanee ed eseguo molte metriche su di essi. L'utilizzo delle tabelle temporanee (o delle funzioni con valori di tabella) ha reso più facili, nel mio caso, molti aspetti dell'elaborazione. – overslacked

2

L'approccio di Tom H funzionerà. È possibile semplificare in questo modo se si dispone di una colonna di identità:

SELECT T1.id, T1.value_column1, avg(T2.value_column1) 
FROM table1 T1 
INNER JOIN table1 T2 ON T2.Id BETWEEN T1.Id-19 AND T1.Id 
+0

Non so MySQL, ma in MS SQL Server non funzionerà. Le colonne IDENTITY non possono essere sequenziali o contigue. –

+0

Saranno, se non si utilizza SET IDENTITY_INSERT ON o si eliminano i prezzi? In questo caso, è possibile spostare i dati su una tabella temporanea con una colonna Identity ordinata per data. – Andomar

+0

Sono d'accordo con Tom. Un'IDENTITÀ (o in linguaggio MySQL, una chiave primaria auto_increment) non può essere sequenziale o contigua. Cosa succede se elimini alcune righe dal centro del tavolo? Avresti delle lacune nella chiave. –

0

Nella mia esperienza, MySQL dalla 5.5.x tende a non utilizzare gli indici su seleziona dipendenti, se un subquery o unirsi. Ciò può avere un impatto molto significativo sulle prestazioni in cui i criteri di selezione dipendenti cambiano su ogni riga.

La media mobile è un esempio di una query che rientra in questa categoria. Il tempo di esecuzione può aumentare con il quadrato delle file. Per evitare ciò, scegliere un motore di database in grado di eseguire ricerche indicizzate su selezioni dipendenti. Trovo che postgres funzioni efficacemente per questo problema.

1

La mia soluzione aggiunge un numero di riga nella tabella. Il seguente codice di esempio può aiutare:

set @MA_period=5; 
select id1,tmp1.date_time,tmp1.c,avg(tmp2.c) from 
(select @b:[email protected]+1 as id1,date_time,c from websource.EURUSD,(select @b:=0) bb order by date_time asc) tmp1, 
(select @a:[email protected]+1 as id2,date_time,c from websource.EURUSD,(select @a:=0) aa order by date_time asc) tmp2 
where id1>@MA_period and id1>=id2 and id2>([email protected]_period) 
group by id1 
order by id1 asc,id2 asc 
+0

nel caso in cui si usi una condizione per selezionare record specifici dalla tabella (qui denominata websource.EURUSD) è necessario utilizzare esattamente la stessa condizione in entrambi i sottoselezionamenti (alias tmp1 e tmp2) –

1

Mi rendo conto che questa risposta è di circa 7 anni di ritardo. Avevo un requisito simile e pensavo di condividere la mia soluzione nel caso fosse utile a qualcun altro.

Ci sono alcune estensioni MySQL per analisi tecniche che includono una media mobile semplice. Sono veramente facile da installare e utilizzare: https://github.com/mysqludf/lib_mysqludf_ta#readme

Una volta installato l'UDF (secondo le istruzioni nel README), è possibile includere una media mobile semplice in una dichiarazione prescelta come questo:

SELECT TA_SMA(value_column1, 20) AS sma_20 FROM table1 ORDER BY datetime_column1 
Problemi correlati