W poprzednim poście zaczęliśmy opowiadanie o tym, czym jest NULL i jak się zachowuje. Dzisiejszym postem kontynuujemy ten temat.
W SQL wyrażenia, które zawierają w sobie NULL zawsze zwracają nieznany wynik. Przykładem mogą być takie operacje:
+------+--------+----------------------+---------------------+
| NULL | 5+NULL | CONCAT('tekst',NULL) | FROM_UNIXTIME(NULL) |
+------+--------+----------------------+---------------------+
| NULL | NULL | NULL | NULL |
+------+--------+----------------------+---------------------+
1 row in set (0.00 sec)
To samo będzie w przypadku użycia wyrażenia z NULL w warunku WHERE:
+------+------+
| a | b |
+------+------+
| 0 | |
| 0 | NULL |
| NULL | NULL |
+------+------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM tab_null WHERE b=NULL;
Empty set (0.00 sec)
Aby sprawdzić, które rekordy zawierają NULL w kolumnie ‘b’ konieczne jest zastosowanie operatora IS NULL. Analogicznie, aby sprawdzić które nie zawierają NULL wykorzystujemy IS NOT NULL:
+------+------+
| a | b |
+------+------+
| 0 | NULL |
| NULL | NULL |
+------+------+
2 rows in set (0.00 sec)
mysql> SELECT * FROM tab_null WHERE b IS NOT NULL;
+------+------+
| a | b |
+------+------+
| 0 | |
+------+------+
1 row in set (0.00 sec)
Jeśli chcemy wyciągnąć informację o rekordach z pustą kolumną ‘b’ wystarczy oczywiście standardowe zapytanie:
+------+------+
| a | b |
+------+------+
| 0 | |
+------+------+
1 row in set (0.00 sec)
Jeśli stosujemy funkcje agregujące kolumny typu COUNT(), MAX(), SUM(), MIN() itp. ignorują one rekordy z wartością NULL. Odstępstwem jest COUNT(*) – tak wywołana zlicza wszystkie rekordy a nie wartości występujące w kolumnie. Przykładowo:
+------+------+
| a | b |
+------+------+
| 0 | |
| 0 | NULL |
| NULL | NULL |
+------+------+
3 rows in set (0.00 sec)
mysql> SELECT COUNT(a), COUNT(b), COUNT(*) FROM tab_null;
+----------+----------+----------+
| COUNT(a) | COUNT(b) | COUNT(*) |
+----------+----------+----------+
| 2 | 1 | 3 |
+----------+----------+----------+
1 row in set (0.00 sec)
W przypadku zastosowania sortowania NULL traktowana jest jako minus nieskończoność – będzie na początku gdy sortujemy rosnąco i na końcu, gdy sortujemy malejąco.
+------+------+
| a | b |
+------+------+
| 0 | NULL |
| NULL | NULL |
| 0 | |
+------+------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM tab_null ORDER BY b DESC;
+------+------+
| a | b |
+------+------+
| 0 | |
| 0 | NULL |
| NULL | NULL |
+------+------+
3 rows in set (0.00 sec)
Innymi ciekawymi cechami NULL jest np. to, że jeśli do kolumny o typie TIMESTAMP wrzucimy wartość NULL, to w efekcie dodaną do tabeli wartością tej kolumny będzie aktualna data i czas.
Edit.
Powyższe jest prawdziwe tylko dla tabel tworzonych w sposób następujący:
W takiej sytuacji MySQL domyślnie dodaje DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP do definicji kolumny b:
*************************** 1. row ***************************
Table: tab
Create Table: CREATE TABLE `tab` (
`a` int(11) DEFAULT NULL,
`b` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=MyISAM DEFAULT CHARSET=latin2
1 row in set (0,00 sec)
Nie można zakładać że tak będzie zawsze, bo można także jako wartość domyślną dla kolumny TIMESTAMP ustawić NULL. Wtedy tego typu zastąpienie NULL konkretną aktualnym czasem nie ma miejsca:
Query OK, 0 rows affected (0,02 sec)
mysql> INSERT INTO tab VALUES (1, NULL);
Query OK, 1 row affected (0,00 sec)
mysql> drop table tab;
Query OK, 0 rows affected (0,00 sec)
mysql> CREATE TABLE tab (a INT, b TIMESTAMP NULL);
Query OK, 0 rows affected (0,04 sec)
mysql> SHOW CREATE TABLE tab\G
*************************** 1. row ***************************
Table: tab
Create Table: CREATE TABLE `tab` (
`a` int(11) DEFAULT NULL,
`b` timestamp NULL DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin2
1 row in set (0,00 sec)
mysql> INSERT INTO tab VALUES (1, NULL);
Query OK, 1 row affected (0,00 sec)
mysql> SELECT * FROM tab;
+------+------+
| a | b |
+------+------+
| 1 | NULL |
+------+------+
1 row in set (0,00 sec)
Dziękuję Marcie za zwrócenie uwagi na to zachowanie.
Jeśli dodamy NULL do kolumny, która jest autoinkrementowana, wstawiana jest kolejna z rzędu wartość. W przypadku GROUP BY, ORDER BY czy DISTINCT wszystkie wartości NULL traktowane są jako identyczne.
Mam nadzieję, że tą serią postów trochę przybliżyłem specyficzne zjawisko, jakim jest w SQL wartość NULL. Te dwa posty tu dopiero początek na drodze ku poznaniu. Ciekawe i nie koniecznie logicznie przewidywalne rzeczy zaczynają się dziać w momencie gdy NULL pojawia się w JOINach. Może w przyszłości trafi to na ten blog, na razie zainteresowanych zapraszam do dokumentacji MySQL i do podręczników opisujących SQL.
Komentarze