2012-01-17 11 views
18

Potrzebuję napisać zapytanie, które zwraca sumę wszystkich wartości, które spełniają określone kryteria, ale zapytanie musi zwrócić 0, jeśli nie znaleziono żadnych wierszy, zamiast wartości zerowej. Na przykład:Jak wybrać sumę-lub-0, jeśli nie istnieją żadne rekordy?

tab  
+---------------+-----+ 
| descr   | num | 
+---------------+-----+ 
| hello there | 5 | 
| hi there  | 10 | 
| hello   | 10 | 
| hi there!  | 15 | 
+---------------+-----+ 

tego zapytania:

SELECT sum(num) AS val FROM tab WHERE descr LIKE "%hello%"; 

powinien, a nie, wróć 15. Jednakże:

SELECT sum(num) AS val FROM tab WHERE descr LIKE "%greetings%"; 

powinien powrócić 0, ale ma wrócić null.

Czy ktoś może wyjaśnić, czy jest to możliwe?

Odpowiedz

44

Jak o:

SELECT COALESCE(sum(num), 0) AS val FROM tab WHERE descr LIKE "%greetings%"; 

Funkcja COALESCE zasadzie mówi „powrót pierwszego parametru, chyba że jest to wartość null w takim przypadku zwrócić drugi parametr” - Jest to bardzo przydatny w tych scenariuszach.

+0

Nie przynosi to pożądanego efektu - spowoduje to również maskowanie wartości "NULL", która jest częścią samych wartości "num". –

+0

Działa, świetne rozwiązanie – nitin

1

to działa:

SELECT IF(SUM(num) IS NULL, 0, SUM(num)) AS val FROM tab WHERE descr LIKE "%whatever%"; 

IF() pobiera trzy parametry: (1) Oświadczenie, (2) wartość do zastosowania, jeśli zdanie jest prawdziwe, oraz (3) wartość do zastosowania, jeżeli oświadczenie jest fałszywe.

8

Sprawdź MySQL documentation for IFNULL.

SELECT SUM(IFNULL(num, 0)) as val FROM tab WHERE descr LIKE "%greetings%"; 

Oczywiście, to zakłada się, że pole num jest pustych i nie ma wartości domyślnej. Innym możliwym rozwiązaniem byłoby ustawienie wartości domyślnej 0 dla pola num, które powinno rozwiązać problem, który masz.

+6

IFNULL powinien znajdować się poza SUMĄ, w przeciwnym razie, jeśli nie zostaną znalezione żadne wiersze, zwróci wartość null. –

0

Aby to zrobić poprawnie, możesz chcieć rozróżnić przypadki, w których są rzeczywiste wyniki NULL w sumowanych danych, oraz przypadek, w którym nie ma żadnych sum.

Załóżmy, że mamy następujące:

mysql> select * from t; 
+----------+------+ 
| descr | num | 
+----------+------+ 
| hiya  | 5 | 
| hi there | 10 | 
| yo  | NULL | 
+----------+------+ 

Chcielibyśmy pustych sumy wynosi zero, ale sumy udziałem NULL być NULL. Jeden (raczej męczący) sposób to zrobić:

mysql> SELECT IF(has_null, NULL, total) AS sum FROM (
    -> SELECT COALESCE(MAX(num IS NULL), 0) AS has_null, COALESCE(SUM(num), 0) AS total 
    -> FROM t WHERE num < 'ciao') 
    -> AS u; 
+------+ 
| sum | 
+------+ 
| 0 | 
+------+ 
1 row in set, 1 warning (0.00 sec) 

mysql> SELECT IF(has_null, NULL, total) AS sum FROM (
    -> SELECT COALESCE(MAX(num IS NULL), 0) AS has_null, COALESCE(SUM(num), 0) AS total 
    -> FROM t) 
    -> AS u; 
+------+ 
| sum | 
+------+ 
| NULL | 
+------+ 
1 row in set (0.00 sec) 

mysql> SELECT IF(has_null, NULL, total) AS sum FROM (
    -> SELECT COALESCE(MAX(num IS NULL), 0) AS has_null, COALESCE(SUM(num), 0) AS total 
    -> FROM t WHERE descr < 'namaste') 
    -> AS u; 
+------+ 
| sum | 
+------+ 
| 15 | 
+------+ 
1 row in set (0.00 sec) 

mysql> SELECT IF(has_null, NULL, total) AS sum FROM (
    -> SELECT COALESCE(MAX(num IS NULL), 0) AS has_null, COALESCE(SUM(num), 0) AS total 
    -> FROM t WHERE descr > 'namaste') 
    -> AS u; 
+------+ 
| sum | 
+------+ 
| NULL | 
+------+ 
1 row in set (0.00 sec) 

Być może jest lepszy sposób, o którym nie pomyślałem.

Niestety, standard SQL defines SUM to be null when no elements are summed i MySQL nie mają wyboru, muszą przestrzegać tego standardu.