2012-12-24 15 views
12

Co I'am sposób:Strange MySQL średnia() wartości anomalii NULL

create table sample (id INT(10) PRIMARY KEY AUTO_INCREMENT,name varchar(255),marks INT(10)); 

insert into sample (name,marks) VALUES('sam',10); 
insert into sample (name,marks) VALUES('sam',20); 
insert into sample (name,marks) VALUES('sam',NULL); 
insert into sample (name,marks) VALUES('sam',NULL); 
insert into sample (name,marks) VALUES('sam',30); 

select AVG(marks) from sample GROUP BY(name); 

napędzanych i Przewidywana

AVG = (10 + 20 + 30)/5 = 12

WYJŚCIE MySQL:

AVG = (10 + 20 + 30)/3 = 20

Idealnie co chciałem to, że MySQL powinien dostać sumę 5 rzędów i podzielić ją przez 5, ale dzieli tylko 3 (wiersze inne niż NULL)

Dlaczego tak się dzieje i co mogę zrobić, aby uzyskać prawidłowy AVG, czyli 60/5? PS: Nie mogę uczynić pola znaczników NOT NULL, w moim projekcie bazy danych pole znaków może mieć wartość NULL.

Dziękuję

+1

dodaje jeszcze więcej wyjaśnień i odwołań do mojej odpowiedzi – Kaii

+0

dzięki @Kaii które pomogły :) –

Odpowiedz

33

Jest to poprawne zachowanie, ponieważ NULL nie jest taka sama jak liczba 0.

Koncepcyjnie, NULL oznacza "brakującą nieznaną wartość" i jest traktowane nieco inaczej niż inne wartości. Dlatego aggregate functions jak AVG() zignorować NULL s.

oblicza średnią tylko dla wszystkich wartości określonych. (= będące nie NULL)

Z MySQL docs:

ile nie zaznaczono inaczej, funkcje grupy ignorować wartości NULL.

Przeczytaj również o koncepcji NULL s w Section "3.3.4.6 Working with NULL Values" podręcznika MySQL.

Aby dostać to, co chcesz, możesz zrobić

SELECT AVG(IFNULL(marks, 0)) FROM sample GROUP BY(name); 

IFNULL() zwraca drugi argument dla obliczeń, jeśli wartość jest NULL lub przechodzi przez wartość inaczej.


Są bardziej powszechne nieporozumienia dotyczące koncepcji NULL. Są także wyjaśnione Section "5.5.3 Problems with NULL" podręcznika:

  • W SQL Opcja `wartość NULL` nigdy nie jest prawdą w stosunku do jakiejkolwiek innej wartości, nawet` NULL`. Wyrażenie zawierające "NULL" zawsze daje wartość "NULL", chyba że w dokumentacji dla operatorów i funkcji związanych z wyrażeniem podano inaczej.

    tj.: `NULL == 0` daje NULL zamiast` true`. Również `NULL == NULL` daje NULL, zamiast wartości true.
  • Aby wyszukać wartości kolumn o wartości "NULL", nie można użyć testu `expr = NULL`. Aby wyszukać wartości `NULL`, musisz użyć testu` IS NULL`.
  • Podczas używania "DISTINCT", "GROUP BY" lub "ORDER BY" wszystkie wartości "NULL" są traktowane jako równe.
  • Podczas korzystania `` ORDER BY` wartości NULL` są przedstawiane pierwszy lub ostatni jeśli podasz `DESC` sortowania w kolejności malejącej.
  • Dla niektórych typów danych MySQL obsługuje szczególnie wartości NULL. Jeśli wstawisz `NULL` do kolumny` TIMESTAMP`, wstawiana jest aktualna data i godzina.
  • Jeśli wstawisz `NULL` do liczby całkowitej lub zmiennoprzecinkowej z atrybutem` AUTO_INCREMENT`, wstawiany jest następny numer w sekwencji.
  • Kolumna ze zdefiniowanym kluczem "UNIQUE" może nadal zawierać wiele wartości "NULL".
+0

dzięki @kaii, że rozwiązanie pomogło, byłem pod wrażeniem wykonanej mySQL jak AVG = suma/(nos kolumn w wyniku) –

2

Spróbuj:

select avg(case marks when null then 0 else marks end) from sample group by name; 

Albo spróbować uniknąć null w tabeli;)

+0

dzięki za pomoc @fge –

1

Można to zrobić w zamian:

SELECT SUM(marks)/COUNT(name) 
FROM sample 
GROUP BY name; 
1

To normalne zachowanie, ponieważ NULL nie jest zero. Jak zrobić średnią 5 + NULL? Tak więc MySQL pobiera tylko te wiersze, które można uśrednić.

Appart z poprawnych odpowiedzi, które inni użytkownicy już wam udostępnili, można również użyć funkcji COALESCE, która zwraca pierwszą nie-NULL wartość określoną na liście, dzięki czemu można zastąpić NULL jedną z tych, które lubisz :

SELECT AVG(COALESCE(marks,0)) FROM sample GROUP BY(name);