Autor Zpráva
vojak.p
Profil
Zdravím, v databázi mam sloupeček datetime a value, standartně jsou tam uloženy vzorky po minutě(potřebuji zachovat vteřiny). Tyto hodnoty potom zobrazuji v grafu na PHP. Občas se ale někdy mezi vzorkama vytvoří hodinová mezera, jindy zase třeba vteřinová. Potřebuji tedy navrhnout funkci, aby nastavila čas, podívala se do DB, a přiřadila příslušnou hodnotu, v případě že tam nebude, přiřadí NULL. Inkrementuju minutu a opět se podívám do DB. Tím projedu všechny hodnoty. Chci takto vytáhnout hodnoty pro dnešní den - 2 dni zpět, to je 60*24*2=2880 až 60*24*3=4320 hodnot. Jak by bylo nejlepší to udělat?
Tori
Profil
4320 hodnot => min.4.5k pixelů, to bude pěkně velký graf...

Jinak asi šetrnější algoritmus by byl:

nastavím do proměnné $čas začátek zobrazovaného období (jako timestamp)
provedu SQL dotaz pro zjištění všech záznamů mladších než $čas
načtu řádek dat z DB do $row
dokud $čas < teď :    
    pokud čas v $row === $čas :
        zobrazím hodnotu z $row
        načtu další řádek dat z DB do $row
    jinak :
        zobrazím NULL
    hodnotu $čas zvýším o 1
konec cyklu 
(odpadne to neefektivní "opět se podívám do DB")
vojak.p
Profil
Tori:
Ano, nějak takto bych to chtěl, ale jak udělat tu podmínku s časama? Mam porovnávat datum převedený na vteřiny? Jak udělám tu proměnou čas, chci něco ve stylu 2013-09-08 0:00:00 + 123 minutes = 2013-09-08 2:03:00? Jak mam porovnat čas 2:03:15 s 2:03:00 abych dostal shodu?
Tori
Profil
1. datum si nastavíte např. pomocí strtotime (něco jako "now - 48 hours", projděte si manuál ohledně zápisu relativních časů), zformátujete pomocí date('Y-m-d 00:00:00', $time).
2. v SQL dotazu ten zformátovaný čas použijete úplně jednoduše ...WHERE sloupecDatetime > '$cas', můžete si ho nechat vypsat rovnou jako timestamp (viz MySQL funkce UNIX_TIMESTAMP)

edit: Asi jsem nepochopila, s jakými časy jsou záznamy uložené. Jestli potřebujete použít něco jako "jakýkoli záznam vložený během této minuty", tak si datum ještě zaokrouhlete např. na celé minuty (pomocí DATE_FORMAT), až pak převeďte na timestamp. V PHP se musí také počítat s časy, které mají 0 vteřin: 02:02:00, 02:03:00, ...
vojak.p
Profil
Asi si nerozumíme. V DB mam čas uložený jako datetime. Potřebuji vytáhnout všechny hodnoty které jsou například v rozmení 1.9.2013 0:00:00 - 4.9.2013 0:00:00, pak je potřebuji jednotlivě zkontrolovat, v jedné minutě smí být jen jedna hodnota, další zahazuju. Chybí-li hodnota, doplním NULL. Poté výsledky zobrazím.
Taps
Profil
vojak.p:
tak zkus operátor between
Tori
Profil
vojak.p:
pak je potřebuji jednotlivě zkontrolovat, v jedné minutě smí být jen jedna hodnota, další zahazuju
SELECT *, UNIX_TIMESTAMP(DATE_FORMAT(datum, '%Y-%m-%d %H:%i:00')) ts
FROM tabulka 
WHERE datum BETWEEN '$od' AND '$do'
GROUP BY ts
vojak.p
Profil
tak jsem to zatím navrhl takto:
vyčtu z databáze čas a k tomu proměnou za poslední 3 dny. Proženu to for cyklem, který kontroluje, zda rozdíl mezi
$cas[$i] a $cas[$i+1] je větší jak 59. Tím vyloučím kratší intervaly. Poté zkontroluju jestli ten rozdíl je menší jak 120, omezím se na minutový interval, a zapíšu $value_new = $value. Je-li větší $value_new = NULL a k $cas[$i] přičtu 60 a znovu kontoluju. Tím vytvořím kompletní časovou osu po minutě. Celý script generování obrázku se zpozdí o 100ms, z 350 na 420ms, při 4320 hodnotách.
PostCC
Profil
vojak.p:
Zajímalo by mne, proč musí ta časová osa být kompletní? Za den to znamená 1440, za tři dny tedy skutečně 4320 hodnot. To je megagraf.

Řešil jsem něco podobného a dospěl jsem k výsledku pomocí "časové osy", uzpůsobené šířce grafu. Hodnoty (výšky sloupců) pak mohou nabývat například maximálních, minimálních nebo průměrných hodnot v daném intervalu za předpokladu, že jeden sloupec neznamená jednu minutu, ale proměnný časový úsek. Do takto koncipovaného grafu lze pak nacpat libovolný časový interval s tím, že "rozsah" sloupce se automaticky uzpůsobí požadované šířce grafu. Dotaz pak vypadá nějak takto:

SELECT
    FLOOR(TIME_TO_SEC(TIMEDIFF(T.Cas, '$Since')) / (TIME_TO_SEC(TIMEDIFF('$Until', '$Since')) / $GraphColumnCount)) AS TimeLine,
    T.Promenna AS Root,
    MAX(Hodnota) AS Pocet
FROM
    THodnota AS T
WHERE
    T.Cas BETWEEN '$Since' AND '$Until'
GROUP BY
    FLOOR(TIME_TO_SEC(TIMEDIFF(T.Cas, '$Since')) / (TIME_TO_SEC(TIMEDIFF('$Until', '$Since')) / $GraphColumnCount)),
    Root
ORDER BY
    TimeLine,
    Root

Takto koncipovaný graf může pak obsahovat i více různých křivek (sloupců) pro různé veličiny, typicky teploty z více měřících stanic. Vstupem je časový inteval ($Since, $Until) a počet sloupců ($GraphColumnCount).

Ve sloupci "TimeLine" je ve výsledku číslo sloupce v grafu, hodnoty nabývají rozsahu 0 - ($GraphColumnCount - 1).

Výšky sloupců jsou obsaženy v "Pocet", agregační funkce určuje o jaké hodnoty půjde.

Nabízím k úvaze pro použití, neznám pochopitelně přesné zadání, takže možná to stejně nevyhoví.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: