В1:Защо базата данни не връща валидна стойност за средната стойност на тези две дати?
А: Върнатата стойност се очаква, това е добре дефинирано поведение на MySQL.
Справочно ръководство за MySQL:https://dev .mysql.com/doc/refman/5.5/en/date-and-time-types.html
В MySQL, AVG
агрегатната функция работи с числови стойности.
В MySQL, DATE
или DATETIME
изразът може да бъде оценен числово контекст.
Като проста демонстрация, извършване на числово операция за добавяне на DATETIME
имплицитно преобразува стойността дата и час в число. Тази заявка:
SELECT NOW(), NOW()+0
връща резултат като:
NOW() NOW()+0
------------------- -----------------------
2015-06-23 17:57:48 20150623175748.000000
Обърнете внимание, че стойността, върната за израза NOW()+0
е не a DATETIME
, това е число .
Когато посочите SUM()
или AVG()
функция на DATETIME
израз, което е еквивалентно на преобразуване на DATETIME
в число и след това сумиране или осредняване на числото.
Тоест връщането от този израз AVG(mydatetimecol)
е еквивалентен на връщането от този израз:AVG(mydatetimecol+0)
Това, което се "осреднява", е числова стойност. И вие сте забелязали, върнатата стойност не е валидна дата и час; и дори в случаите, когато изглежда като валидна дата и час, вероятно не е стойност, която бихте сметнали за истинска „средна стойност“.
В2:Как мога да получа действителната средна стойност на това поле, ако описаният начин е неуспешен?
A2: Един от начините да направите това е да преобразувате датата и часа в числова стойност, която може да бъде „точно“ осреднена, и след това да я преобразувате обратно в дата и час.
Например, можете да преобразувате датата и часа в числова стойност, представляваща брой секунди от някакъв фиксиран момент във времето, напр.
TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)
След това можете да „осредните“ тези стойности, за да получите среден брой секунди от фиксиран момент във времето. (ЗАБЕЛЕЖКА:внимавайте да добавяте изключително голям брой редове с изключително големи стойности и надвишаване на ограничението (максимална числова стойност), проблеми с препълването на числа.)
AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date))
За да го преобразувате обратно в дата и час, добавете тази стойност като брой секунди обратно към фиксирания момент във времето:
'2015-01-01' + INTERVAL AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)) SECOND
(Обърнете внимание, че DATEIME
стойностите се оценяват в часовата зона на сесията на MySQL; така че има крайни случаи, когато настройката на time_zone
променлива в сесията на MySQL ще има известно влияние върху върнатата стойност.)
MySQL също така предоставя UNIX_TIMESTAMP()
функция, която връща цяло число в unix стил, брой секунди от началото на ерата (полунощ на 1 януари 1970 г. UTC). Можете да го използвате, за да извършите същата операция по-сбито:
FROM_UNIXTIME(AVG(UNIX_TIMESTAMP(t.my_date)))
Обърнете внимание, че този окончателен израз наистина прави същото... преобразуване на стойността за дата и време в брой секунди от '1970-01-01 00:00:00' UTC, вземане на средно число от това и след това добавяне на тази средна стойност брой секунди обратно към '1970-01-01' UTC и накрая преобразуване обратно в DATETIME
стойност, представена в текущата сесия time_zone
.
В3:Django DateTimeField не е ли настроен да извършва усредняване на манипулаторите?
А: Очевидно авторите на Django са доволни от стойността, върната от базата данни за SQL израз AVG(datetime)
.