Per cominciare, riassumiamo il numero di voci per ora nella tabella.
SELECT CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) hour,
COUNT(*) samplecount
FROM table
GROUP BY CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME)
Ora, se registri qualcosa ogni sei minuti (dieci volte all'ora), tutti i valori del conteggio dei campioni dovrebbero essere dieci. Questa espressione:CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME)
sembra peloso ma semplicemente tronca i tuoi timestamp all'ora in cui si verificano azzerando minuti e secondi.
Questo è ragionevolmente efficiente e ti consentirà di iniziare. È molto efficiente se puoi inserire un indice nella colonna entry_time e limitare la tua query, diciamo, agli esempi di ieri, come mostrato qui.
SELECT CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME) hour,
COUNT(*) samplecount
FROM table
WHERE entry_time >= CURRENT_DATE - INTERVAL 1 DAY
AND entry_time < CURRENT_DATE
GROUP BY CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME)
Ma non è molto bravo a rilevare intere ore che passano con campioni mancanti. È anche un po' sensibile al jitter nel campionamento. Cioè, se il tuo campione della parte superiore dell'ora è a volte in anticipo di mezzo secondo (10:59:30) e talvolta in ritardo di mezzo secondo (11:00:30), il conteggio del riepilogo orario sarà storto. Quindi, questa cosa del riepilogo dell'ora (o riepilogo del giorno, o riepilogo dei minuti, ecc.) Non è a prova di proiettile.
Hai bisogno di una query di auto-unione per ottenere le cose perfettamente giuste; è un po' più una palla di pelo e non altrettanto efficiente.
Iniziamo creando noi stessi una tabella virtuale (subquery) come questa con campioni numerati. (Questo è un problema in MySQL; alcuni altri DBMS costosi lo rendono più semplice. Non importa.)
SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value
FROM (
SELECT entry_time, value
FROM table
ORDER BY entry_time
) C,
(SELECT @sample:=0) s
Questa piccola tabella virtuale fornisce entry_num, entry_time, valore.
Il prossimo passo, lo uniamo a se stesso.
SELECT one.entry_num, one.entry_time, one.value,
TIMEDIFF(two.value, one.value) interval
FROM (
/* virtual table */
) ONE
JOIN (
/* same virtual table */
) TWO ON (TWO.entry_num - 1 = ONE.entry_num)
Questo allinea i tavoli uno accanto all'altro compensati da un'unica voce, regolata dalla clausola ON del JOIN.
Infine scegliamo i valori da questa tabella con un interval
maggiore della tua soglia e ci sono i tempi dei campioni subito prima di quelli mancanti.
La query di unione automatica generale è questa. Te l'avevo detto che era una palla di pelo.
SELECT one.entry_num, one.entry_time, one.value,
TIMEDIFF(two.value, one.value) interval
FROM (
SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value
FROM (
SELECT entry_time, value
FROM table
ORDER BY entry_time
) C,
(SELECT @sample:=0) s
) ONE
JOIN (
SELECT @sample2:[email protected]+1 AS entry_num, c.entry_time, c.value
FROM (
SELECT entry_time, value
FROM table
ORDER BY entry_time
) C,
(SELECT @sample2:=0) s
) TWO ON (TWO.entry_num - 1 = ONE.entry_num)
Se devi farlo in produzione su una tabella di grandi dimensioni, potresti volerlo fare per un sottoinsieme dei tuoi dati. Ad esempio, potresti farlo ogni giorno per i campioni dei due giorni precedenti. Questo sarebbe abbastanza efficiente e ti assicurerebbe anche di non trascurare alcun campione mancante a mezzanotte. Per fare questo, i tuoi tavolini virtuali numerati di righe assomiglierebbero a questo.
SELECT @sample:[email protected]+1 AS entry_num, c.entry_time, c.value
FROM (
SELECT entry_time, value
FROM table
ORDER BY entry_time
WHERE entry_time >= CURRENT_DATE - INTERVAL 2 DAY
AND entry_time < CURRENT_DATE /*yesterday but not today*/
) C,
(SELECT @sample:=0) s