Mysql
 sql >> Database >  >> RDS >> Mysql

Perché MYSQL DB restituisce un valore danneggiato durante la media su un Django models.DateTimeField?

Q1:Perché il database non restituisce un valore valido per la media di queste due date?

R: Il valore restituito è previsto, è un comportamento MySQL ben definito.

Manuale di riferimento MySQL:https://dev .mysql.com/doc/refman/5.5/en/date-and-time-types.html

In MySQL, il AVG la funzione di aggregazione opera su numerico valori.

In MySQL, un DATE o DATETIME l'espressione può essere valutata in un numerico contesto.

Come semplice dimostrazione, eseguire un numerico operazione di addizione su un DATETIME converte implicitamente il valore datetime in un numero. Questa domanda:

  SELECT NOW(), NOW()+0

restituisce un risultato del tipo:

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

Nota che il valore restituito per l'espressione NOW()+0 è non un DATETIME , è un numero .

Quando specifichi un SUM() o AVG() funzione su un DATETIME espressione, è equivalente alla conversione di DATETIME in un numero, quindi sommare o calcolare la media del numero.

Ovvero, il ritorno da questa espressione AVG(mydatetimecol) è equivalente al ritorno di questa espressione:AVG(mydatetimecol+0)

Ciò che viene "mediato" è un valore numerico. E hai osservato, il valore restituito non è un datetime valido; e anche nei casi in cui sembra un datetime valido, è probabile che non sia un valore che considereresti una vera "media".

D2:Come ottengo la media effettiva di questo campo se il modo descritto non riesce?

A2: Un modo per farlo è convertire il datetime in un valore numerico di cui è possibile calcolare la media "accuratamente" e quindi riconvertirlo in datetime.

Ad esempio, puoi convertire datetime in un valore numerico che rappresenta un numero di secondi da un punto fisso nel tempo, ad es.

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

Puoi quindi "mediare" quei valori, per ottenere un numero medio di secondi da un punto fisso nel tempo. (NOTA:fare attenzione a non sommare un numero estremamente elevato di righe, con valori estremamente grandi, e superare il limite (valore numerico massimo), problemi di overflow numerico.)

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

Per riconvertirlo in un datetime, aggiungi quel valore come numero di secondi torna a un punto fisso nel tempo:

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

(Nota che il DATEIME i valori vengono valutati nel fuso orario della sessione MySQL; quindi ci sono casi limite in cui l'impostazione del time_zone variabile nella sessione MySQL avrà una certa influenza sul valore restituito.)

MySQL fornisce anche un UNIX_TIMESTAMP() funzione che restituisce un valore intero in stile unix, numero di secondi dall'inizio dell'era (mezzanotte 1 gennaio 1970 UTC). Puoi usarlo per eseguire la stessa operazione in modo più conciso:

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

Nota che questa espressione finale sta facendo davvero la stessa cosa... convertendo il valore datetime in un numero di secondi da '1970-01-01 00:00:00' UTC, prendendo una media numerica di quello e quindi aggiungendo quella media numero di secondi per tornare a "1970-01-01" UTC e infine riconvertirlo in un DATETIME valore, rappresentato nella sessione corrente time_zone .

T3:Django DateTimeField non è configurato per gestire la media?

R: Apparentemente, gli autori di Django sono soddisfatti del valore restituito dal database per un'espressione SQL AVG(datetime) .