Mysql
 sql >> Base de données >  >> RDS >> Mysql

Pourquoi MYSQL DB renvoie-t-il une valeur corrompue lors de la moyenne sur un Django models.DateTimeField ?

Q1 :Pourquoi la base de données ne renvoie-t-elle pas une valeur valide pour la moyenne de ces deux dates ?

R : La valeur retournée est attendue, c'est un comportement MySQL bien défini.

Manuel de référence MySQL :https://dev .mysql.com/doc/refman/5.5/en/date-and-time-types.html

Dans MySQL, le AVG la fonction d'agrégation fonctionne sur numérique valeurs.

Dans MySQL, une DATE ou DATETIME l'expression peut être évaluée dans un numérique contexte.

À titre de démonstration simple, effectuer une opération numérique opération d'addition sur un DATETIME convertit implicitement la valeur datetime en nombre. Cette requête :

  SELECT NOW(), NOW()+0

renvoie un résultat comme :

  NOW()                                NOW()+0  
  -------------------  -----------------------
  2015-06-23 17:57:48    20150623175748.000000

Notez que la valeur renvoyée pour l'expression NOW()+0 n'est pas un DATETIME , c'est un nombre .

Lorsque vous spécifiez un SUM() ou AVG() fonction sur un DATETIME expression, cela équivaut à convertir le DATETIME en un nombre, puis en additionnantou en faisant la moyenne du nombre.

Autrement dit, le retour de cette expression AVG(mydatetimecol) est équivalent au retour de cette expression :AVG(mydatetimecol+0)

Ce qui est "moyenne" est une valeur numérique. Et vous avez observé que la valeur renvoyée n'est pas une date/heure valide ; et même dans les cas où cela ressemble à une date/heure valide, ce n'est probablement pas une valeur que vous considéreriez comme une véritable "moyenne".

Q2 :Comment puis-je obtenir la moyenne réelle de ce champ si la méthode décrite échoue ?

A2 : Une façon de le faire est de convertir la date/heure en une valeur numérique dont la moyenne peut être "précise", puis de la reconvertir en date/heure.

Par exemple, vous pouvez convertir la date/heure en une valeur numérique représentant un nombre de secondes à partir d'un point fixe dans le temps, par exemple

  TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)

Vous pouvez ensuite "faire la moyenne" de ces valeurs, pour obtenir un nombre de secondes moyen à partir d'un point fixe dans le temps. (REMARQUE :méfiez-vous de l'addition d'un nombre extrêmement élevé de lignes, avec des valeurs extrêmement élevées, et du dépassement de la limite (valeur numérique maximale), problèmes de dépassement numérique.)

  AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date))

Pour reconvertir cela en une date/heure, ajoutez cette valeur sous forme de nombre de secondes retour à un point fixe dans le temps :

  '2015-01-01' + INTERVAL AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)) SECOND

(Notez que le DATEIME les valeurs sont évaluées dans le fuseau horaire de la session MySQL ; il y a donc des cas extrêmes où le réglage du time_zone variable dans la session MySQL aura une certaine influence sur la valeur renvoyée.)

MySQL fournit également un UNIX_TIMESTAMP() fonction qui renvoie une valeur entière de style unix, nombre de secondes depuis le début de l'ère (minuit 1er janvier 1970 UTC). Vous pouvez l'utiliser pour accomplir la même opération de manière plus concise :

  FROM_UNIXTIME(AVG(UNIX_TIMESTAMP(t.my_date)))

Notez que cette expression finale fait vraiment la même chose ... convertir la valeur datetime en un nombre de secondes depuis '1970-01-01 00:00:00' UTC, en prenant une moyenne numérique de cela, puis en ajoutant cette moyenne nombre de secondes de retour à '1970-01-01' UTC, et enfin reconverti en un DATETIME valeur, représentée dans la session en cours time_zone .

Q3 :Django DateTimeField n'est-il pas configuré pour gérer la moyenne ?

R : Apparemment, les auteurs de Django sont satisfaits de la valeur renvoyée par la base de données pour une expression SQL AVG(datetime) .