P1:Dlaczego baza danych nie zwraca prawidłowej wartości średniej z tych dwóch dat?
O: Zwrócona wartość jest oczekiwana, jest to dobrze zdefiniowane zachowanie MySQL.
Podręcznik MySQL Reference:https://dev .mysql.com/doc/refman/5.5/en/daty-i-godziny.html
W MySQL AVG
funkcja agregująca działa na liczbie wartości.
W MySQL DATE
lub DATETIME
wyrażenie może być ocenione jako liczba kontekst.
W ramach prostej demonstracji wykonanie numerycznego operacja dodawania na DATETIME
niejawnie konwertuje wartość daty i godziny na liczbę. To zapytanie:
SELECT NOW(), NOW()+0
zwraca wynik taki jak:
NOW() NOW()+0
------------------- -----------------------
2015-06-23 17:57:48 20150623175748.000000
Zwróć uwagę, że wartość zwracana dla wyrażenia NOW()+0
jest nie a DATETIME
, to liczba .
Kiedy określisz SUM()
lub AVG()
funkcja na DATETIME
wyrażenie, które jest równoważne konwersji DATETIME
na liczbę, a następnie zsumowanie lub uśrednienie liczby.
Oznacza to, że zwrot z tego wyrażenia AVG(mydatetimecol)
jest odpowiednikiem zwrotu z tego wyrażenia:AVG(mydatetimecol+0)
To, co jest „uśredniane”, jest wartością liczbową. Zauważyłeś, że zwrócona wartość nie jest prawidłową datą i godziną; a nawet w przypadkach, gdy wygląda to na prawidłową datę i godzinę, prawdopodobnie nie jest to wartość, którą uważasz za prawdziwą „średnią”.
P2:Jak uzyskać rzeczywistą średnią tego pola, jeśli opisany sposób nie powiedzie się?
A2: Jednym ze sposobów, aby to zrobić, jest przekonwertowanie daty i godziny na wartość liczbową, którą można „dokładnie” uśrednić, a następnie przekonwertować ją z powrotem na datę i godzinę.
Na przykład możesz przekonwertować datę i godzinę na wartość liczbową reprezentującą liczbę sekund od pewnego ustalonego punktu w czasie, np.
TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)
Następnie możesz „uśrednić” te wartości, aby uzyskać średnią liczbę sekund od ustalonego punktu w czasie. (UWAGA:uważaj na sumowanie bardzo dużej liczby wierszy, z bardzo dużymi wartościami i przekraczaniem limitu (maksymalna wartość liczbowa), problemy z przepełnieniem liczbowym.)
AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date))
Aby przekonwertować to z powrotem na datę i godzinę, dodaj tę wartość jako liczbę sekund powrót do ustalonego punktu w czasie:
'2015-01-01' + INTERVAL AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)) SECOND
(Zauważ, że DATEIME
wartości są oceniane w strefie czasowej sesji MySQL; więc istnieją skrajne przypadki, w których ustawienie time_zone
zmienna w sesji MySQL będzie miała pewien wpływ na zwracaną wartość.)
MySQL udostępnia również funkcję UNIX_TIMESTAMP()
funkcja zwracająca uniksową wartość całkowitą, liczbę sekund od początku ery (północ 1 stycznia 1970 UTC). Możesz użyć tego, aby wykonać tę samą operację w bardziej zwięzły sposób:
FROM_UNIXTIME(AVG(UNIX_TIMESTAMP(t.my_date)))
Zauważ, że to końcowe wyrażenie naprawdę robi to samo… konwertuje wartość daty i godziny na liczbę sekund od czasu UTC „1970-01-01 00:00:00”, biorąc średnią liczbową z tego, a następnie dodając tę średnią liczba sekund z powrotem do „1970-01-01” UTC i ostatecznie przekonwertowanie tego z powrotem na DATETIME
wartość reprezentowana w bieżącej sesji time_zone
.
P3:Czy Django DateTimeField nie jest skonfigurowany do obsługi uśredniania?
O: Najwyraźniej autorzy Django są zadowoleni z wartości zwracanej z bazy danych dla wyrażenia SQL AVG(datetime)
.