Otázka 1:Proč databáze nevrací platnou hodnotu pro průměr těchto dvou dat?
Odpověď: Vrácená hodnota se očekává, je to dobře definované chování MySQL.
Referenční příručka MySQL:https://dev .mysql.com/doc/refman/5.5/en/date-and-time-types.html
V MySQL je to AVG
agregační funkce funguje na numerických hodnoty.
V MySQL, DATE
nebo DATETIME
výraz lze vyhodnotit jako numerický kontextu.
Jako jednoduchou ukázku provedení numerického operace přidání v DATETIME
implicitně převede hodnotu datetime na číslo. Tento dotaz:
SELECT NOW(), NOW()+0
vrátí výsledek jako:
NOW() NOW()+0
------------------- -----------------------
2015-06-23 17:57:48 20150623175748.000000
Všimněte si, že hodnota vrácená pro výraz NOW()+0
není a DATETIME
, je to číslo .
Když zadáte SUM()
nebo AVG()
funkce v DATETIME
výraz, což je ekvivalentní převodu DATETIME
do čísla a poté sečtením nebo zprůměrováním čísla.
Tedy návrat z tohoto výrazu AVG(mydatetimecol)
je ekvivalentní návratu z tohoto výrazu:AVG(mydatetimecol+0)
To, co je "průměrováno", je číselná hodnota. Všimli jste si, že vrácená hodnota není platné datum a čas; a dokonce i v případech, kdy to náhodou vypadá jako platné datum a čas, pravděpodobně to není hodnota, kterou byste považovali za skutečný „průměr“.
O2:Jak získám skutečný průměr tohoto pole, pokud popsaný způsob selže?
A2: Jedním ze způsobů, jak toho dosáhnout, je převést datum a čas na číselnou hodnotu, kterou lze "přesně" zprůměrovat, a poté ji převést zpět na datum a čas.
Můžete například převést datum a čas na číselnou hodnotu představující počet sekund od nějakého pevného bodu v čase, např.
TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)
Poté můžete tyto hodnoty „zprůměrovat“ a získat průměrný počet sekund z pevného bodu v čase. (POZNÁMKA:Dejte si pozor na sčítání extrémně velkého počtu řádků s extrémně velkými hodnotami a překročení limitu (maximální číselné hodnoty), problémy s přetečením čísel.)
AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date))
Chcete-li to převést zpět na datum a čas, přidejte tuto hodnotu jako počet sekund zpět k pevnému bodu v čase:
'2015-01-01' + INTERVAL AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)) SECOND
(Všimněte si, že DATEIME
hodnoty jsou vyhodnocovány v časovém pásmu relace MySQL; takže existují okrajové případy, kdy nastavení time_zone
proměnná v relaci MySQL bude mít určitý vliv na vrácenou hodnotu.)
MySQL také poskytuje UNIX_TIMESTAMP()
funkce, která vrací celočíselnou hodnotu unixového stylu, počet sekund od začátku éry (o půlnoci 1. ledna 1970 UTC). Můžete to použít ke stručnějšímu provedení stejné operace:
FROM_UNIXTIME(AVG(UNIX_TIMESTAMP(t.my_date)))
Všimněte si, že tento konečný výraz skutečně dělá to samé... převádí hodnotu datetime na počet sekund od '1970-01-01 00:00:00' UTC, vezme z toho číselný průměr a pak tento průměr přidá počet sekund zpět na '1970-01-01' UTC a nakonec převedení zpět na DATETIME
hodnota, reprezentovaná v aktuální relaci time_zone
.
O3:Není Django DateTimeField nastaven tak, aby zpracovával průměrování?
Odpověď: Autoři Django jsou zjevně spokojeni s hodnotou vrácenou z databáze pro SQL výraz AVG(datetime)
.