Till att börja med, låt oss sammanfatta antalet anmälningar per timme i din tabell.
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)
Nu, om du loggar något var sjätte minut (tio gånger i timmen) bör alla dina samplecount-värden vara tio. Detta uttryck:CAST(DATE_FORMAT(entry_time,'%Y-%m-%d %k:00:00') AS DATETIME)
ser hårig ut men den kortar helt enkelt dina tidsstämplar till den timme då de inträffar genom att nollställa minut och sekund.
Detta är rimligt effektivt och kommer att komma igång. Det är mycket effektivt om du kan sätta ett index på kolumnen entry_time och begränsa din fråga till, låt oss säga, gårdagens exempel som visas här.
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)
Men det är inte så bra på att upptäcka hela timmar som går med saknade prover. Det är också lite känsligt för jitter i din sampling. Det vill säga, om ditt toppexemplar ibland är en halv sekund för tidigt (10:59:30) och ibland en halv sekund för sent (11:00:30) kommer dina timsammanfattningar att vara avstängda. Så den här timmessammanfattningen (eller dagssammanfattning, eller minutsammanfattning, etc) är inte skottsäker.
Du behöver en självanslutningsfråga för att få saker helt rätt; det är lite mer av en hårboll och inte alls lika effektivt.
Låt oss börja med att skapa oss en virtuell tabell (underfråga) som denna med numrerade exempel. (Detta är jobbigt i MySQL; vissa andra dyra DBMS:er gör det lättare. Oavsett.)
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
Denna lilla virtuella tabell ger entry_num, entry_time, value.
Nästa steg, vi förenar det med sig självt.
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)
Detta radar upp tabellerna nästa två varandra förskjutna av en enda post, styrd av ON-klausulen i JOIN.
Slutligen väljer vi värdena från denna tabell med ett interval
större än din tröskel, och det finns tidpunkter för proverna precis före de saknade.
Den övergripande självanslutningsfrågan är denna. Jag sa att det var en hårboll.
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)
Om du måste göra detta i produktion på ett stort bord kanske du vill göra det för en delmängd av dina data. Du kan till exempel göra det varje dag för de föregående två dagarnas prover. Detta skulle vara hyfsat effektivt och skulle också se till att du inte förbisåg några saknade prover precis vid midnatt. För att göra detta skulle dina små radnumrerade virtuella bord se ut så här.
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