sql >> Databáze >  >> RDS >> Mysql

Proč MYSQL DB vrací poškozenou hodnotu při zprůměrování přes Django models.DateTimeField?

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) .



  1. Modul Pythonu cx_Oracle modul nebyl nalezen

  2. Je zobrazení MySQL rychlejší než běžný dotaz?

  3. Problémy s typy obsahu při načítání zařízení v Django

  4. Jak porovnat hodnoty Null v MySQL