sql >> Base de Datos >  >> RDS >> Mysql

¿Por qué MYSQL DB devuelve un valor corrupto cuando se promedia sobre Django models.DateTimeField?

P1:¿Por qué la base de datos no devuelve un valor válido para el promedio de estas dos fechas?

R: El valor devuelto es el esperado, es un comportamiento de MySQL bien definido.

Manual de referencia de MySQL:https://dev .mysql.com/doc/refman/5.5/en/date-and-time-types.html

En MySQL, el AVG la función agregada opera en numeric valores.

En MySQL, una DATE o DATETIME expresión se puede evaluar en un numérico contexto.

Como demostración simple, realizando un numérico operación de adición en un DATETIME implícitamente convierte el valor de fecha y hora en un número. Esta consulta:

  SELECT NOW(), NOW()+0

devuelve un resultado como:

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

Tenga en cuenta que el valor devuelto por la expresión NOW()+0 es no un DATETIME , es un número .

Cuando especifica un SUM() o AVG() función en un DATETIME expresión, eso es equivalente a convertir el DATETIME en un número, y luego sumando o promediando el número.

Es decir, el retorno de esta expresión AVG(mydatetimecol) es equivalente al retorno de esta expresión:AVG(mydatetimecol+0)

Lo que se "promedia" es un valor numérico. Y ha observado que el valor devuelto no es una fecha y hora válida; e incluso en los casos en que parece una fecha y hora válida, es probable que no sea un valor que consideraría un verdadero "promedio".

P2:¿Cómo obtengo el promedio real de este campo si falla la forma descrita?

A2: Una forma de hacerlo es convertir la fecha y hora en un valor numérico que se pueda promediar "con precisión" y luego volver a convertirlo en una fecha y hora.

Por ejemplo, podría convertir la fecha y hora en un valor numérico que represente una cantidad de segundos desde algún punto fijo en el tiempo, por ejemplo,

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

A continuación, podría "promediar" esos valores para obtener una cantidad de segundos promedio. desde un punto fijo en el tiempo. (NOTA:tenga cuidado de sumar una cantidad extremadamente grande de filas, con valores extremadamente grandes y exceder el límite (valor numérico máximo), problemas de desbordamiento numérico).

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

Para volver a convertir eso en una fecha y hora, agregue ese valor como un número de segundos volver a un punto fijo en el tiempo:

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

(Tenga en cuenta que el DATEIME los valores se evalúan en la zona horaria de la sesión de MySQL; por lo que hay casos extremos en los que la configuración de la time_zone variable en la sesión de MySQL tendrá alguna influencia en el valor devuelto.)

MySQL también proporciona un UNIX_TIMESTAMP() función que devuelve un valor entero de estilo Unix, número de segundos desde el comienzo de la era (medianoche del 1 de enero de 1970 UTC). Puede usarlo para realizar la misma operación de manera más concisa:

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

Tenga en cuenta que esta expresión final realmente está haciendo lo mismo... convirtiendo el valor de fecha y hora en una cantidad de segundos desde '1970-01-01 00:00:00' UTC, tomando un promedio numérico de eso, y luego sumando ese promedio número de segundos de regreso a '1970-01-01' UTC, y finalmente convertirlo nuevamente a un DATETIME valor, representado en la sesión actual time_zone .

P3:¿Django DateTimeField no está configurado para manejar el promedio?

R: Aparentemente, los autores de Django están satisfechos con el valor devuelto por la base de datos para una expresión SQL AVG(datetime) .