F1:Varför returnerar inte databasen ett giltigt värde för genomsnittet av dessa två datum?
Svar: Det returnerade värdet förväntas, det är väldefinierat MySQL-beteende.
MySQL Reference Manual:https://dev .mysql.com/doc/refman/5.5/en/date-and-time-types.html
I MySQL, AVG
aggregatfunktionen fungerar på numerisk värden.
I MySQL, ett DATE
eller DATETIME
uttryck kan utvärderas i en numerisk sammanhang.
Som en enkel demonstration, utföra en numerisk tilläggsåtgärd på en DATETIME
konverterar implicit datetime-värdet till ett tal. Denna fråga:
SELECT NOW(), NOW()+0
returnerar ett resultat som:
NOW() NOW()+0
------------------- -----------------------
2015-06-23 17:57:48 20150623175748.000000
Observera att värdet som returneras för uttrycket NOW()+0
är inte en DATETIME
, det är ett nummer .
När du anger en SUM()
eller AVG()
funktion på en DATETIME
uttryck, det motsvarar att konvertera DATETIME
till ett tal, och summera sedan ett medelvärde för talet.
Det vill säga returen från detta uttryck AVG(mydatetimecol)
motsvarar returen från detta uttryck:AVG(mydatetimecol+0)
Det som "medelvärdes" är ett numeriskt värde. Och du har observerat att det returnerade värdet inte är en giltig datumtid; och även i fall där det råkar se ut som ett giltigt datum och tid, är det troligen inte ett värde som du skulle betrakta som ett sant "genomsnitt".
F2:Hur får jag det faktiska genomsnittet för detta fält om det beskrivna sättet misslyckas?
A2: Ett sätt att göra det är att konvertera datetime till ett numeriskt värde som kan beräknas "exakt" och sedan konvertera tillbaka det till en datetime.
Du kan till exempel konvertera datetime till ett numeriskt värde som representerar ett antal sekunder från någon fast tidpunkt, t.ex.
TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)
Du kan sedan "genomsnitta" dessa värden för att få ett genomsnittligt antal sekunder från en bestämd tidpunkt. (OBS:akta dig för att lägga ihop ett extremt stort antal rader, med extremt stora värden, och överskrida gränsen (maximalt numeriskt värde), numeriska spillproblem.)
AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date))
För att konvertera tillbaka det till en datum och tid, lägg till det värdet som ett antal sekunder tillbaka till en fast tidpunkt:
'2015-01-01' + INTERVAL AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)) SECOND
(Observera att DATEIME
värden utvärderas i tidszonen för MySQL-sessionen; så det finns kantfall där inställningen av time_zone
variabel i MySQL-sessionen kommer att ha viss inverkan på värdet som returneras.)
MySQL tillhandahåller också en UNIX_TIMESTAMP()
funktion som returnerar ett heltalsvärde i unix-stil, antal sekunder från början av eran (midnatt 1 januari 1970 UTC). Du kan använda det för att utföra samma operation mer kortfattat:
FROM_UNIXTIME(AVG(UNIX_TIMESTAMP(t.my_date)))
Observera att det här slutliga uttrycket verkligen gör samma sak... konverterar datetime-värdet till ett antal sekunder sedan '1970-01-01 00:00:00' UTC, tar ett numeriskt medelvärde av det och lägger sedan till det genomsnittet antal sekunder tillbaka till '1970-01-01' UTC, och slutligen konvertera det tillbaka till en DATETIME
värde, representerat i den aktuella sessionen time_zone
.
F3:Är Django DateTimeField inte konfigurerat för att hantera medelvärdesberäkning?
Svar: Tydligen är författarna till Django nöjda med värdet som returneras från databasen för ett SQL-uttryck AVG(datetime)
.