Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Por que o banco de dados MYSQL retorna um valor corrompido ao calcular a média de um models.DateTimeField do Django?


Q1:Por que o banco de dados não retorna um valor válido para a média dessas duas datas?

R: O valor retornado é esperado, é um comportamento MySQL bem definido.

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

No MySQL, o AVG função agregada opera em numérico valores.

No MySQL, um DATE ou DATETIME expressão pode ser avaliada em um numérico contexto.

Como uma demonstração simples, realizando um numérico operação de adição em um DATETIME converte implicitamente o valor de data e hora em um número. Esta consulta:
  SELECT NOW(), NOW()+0

retorna um resultado como:
  NOW()                                NOW()+0  
  -------------------  -----------------------
  2015-06-23 17:57:48    20150623175748.000000

Observe que o valor retornado para a expressão NOW()+0 é não a DATETIME , é um número .

Quando você especifica um SUM() ou AVG() função em um DATETIME expressão, que é equivalente a converter o DATETIME em um número e, em seguida, somar ou calcular a média do número.

Ou seja, o retorno desta expressão AVG(mydatetimecol) é equivalente ao retorno desta expressão:AVG(mydatetimecol+0)

O que está sendo "média" é um valor numérico. E você observou, o valor retornado não é um datetime válido; e mesmo nos casos em que parece uma data e hora válida, provavelmente não é um valor que você consideraria uma verdadeira "média".

P2:como obtenho a média real desse campo se a maneira descrita falhar?

A2: Uma maneira de fazer isso é converter a data e hora em um valor numérico que pode ser calculado com "precisão" e, em seguida, convertê-lo novamente em uma data e hora.

Por exemplo, você pode converter a data e hora em um valor numérico representando um número de segundos de algum ponto fixo no tempo, e.
  TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)

Você poderia então "fazer a média" desses valores, para obter uma média número de segundos a partir de um ponto fixo no tempo. (OBSERVAÇÃO:cuidado com a adição de um número extremamente grande de linhas, com valores extremamente grandes e excedendo o limite (valor numérico máximo), problemas de estouro numérico.)
  AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date))

Para converter isso de volta para uma data e hora, adicione esse valor como um número de segundos de volta a um ponto fixo no tempo:
  '2015-01-01' + INTERVAL AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)) SECOND

(Observe que o DATEIME os valores são avaliados no fuso horário da sessão do MySQL; portanto, há casos extremos em que a configuração do time_zone variável na sessão MySQL terá alguma influência no valor retornado.)

O MySQL também fornece um UNIX_TIMESTAMP() função que retorna um valor inteiro no estilo unix, número de segundos desde o início da era (meia-noite de 1º de janeiro de 1970 UTC). Você pode usar isso para realizar a mesma operação de forma mais concisa:
  FROM_UNIXTIME(AVG(UNIX_TIMESTAMP(t.my_date)))

Observe que essa expressão final está realmente fazendo a mesma coisa ... convertendo o valor de data e hora em um número de segundos desde '1970-01-01 00:00:00' UTC, obtendo uma média numérica disso e adicionando essa média número de segundos de volta para '1970-01-01' UTC e, finalmente, convertendo-o de volta para um DATETIME valor, representado na sessão atual time_zone .

Q3:O Django DateTimeField não está configurado para lidar com a média?

R: Aparentemente, os autores do Django estão satisfeitos com o valor retornado do banco de dados para uma expressão SQL AVG(datetime) .