Czym jest NULL? Co to za wartość? Jakie ma cechy? Jak zachowuje się w zapytaniach? Czy wartość NULL ma jakąkolwiek wartość? Czym NULL różni się od zera? Czy różni się w ogóle? Wbrew pozorom, te pytania nie są rzadkością – odpowiedź na nie potrafi być problemem także dla administratorów i programistów z dłuższym stażem obcowania z MySQL. Jak to więc z NULL jest?

Logicznie rzecz biorąc, NULL to nic. Nic to z kolei zero. Niestety, to by było na tyle logiki, bo MySQL wcale nie planuje się do niej stosować (podobnie zresztą jak i inne systemy RDBMS). W przypadku MySQL NULL oznacza nieznaną wartość. W efekcie nie da się porównać tej wartości z czymkolwiek innym (no bo jej nie znamy). Dlatego też każdy wynik porównania NULL z czymkolwiek zwróci wartość NULL – to akurat jest logiczne: efekt porównania czegoś z nieznanym będzie nieznany.

mysql> SELECT NULL < 1, NULL > 0, NULL = 10, NULL <> 53;
+----------+----------+-----------+------------+
| NULL < 1 | NULL > 0 | NULL = 10 | NULL <> 53 |
+----------+----------+-----------+------------+
|     NULL |     NULL |      NULL |       NULL |
+----------+----------+-----------+------------+
1 row in set (0.00 sec)

Do sprawdzania czy dana wartość jest NULL służą dwa operatory: IS NULL i IS NOT NULL.

mysql> SELECT 5 IS NULL, 3 IS NOT NULL, NULL IS NULL, NULL IS NOT NULL;
+-----------+---------------+--------------+------------------+
| 5 IS NULL | 3 IS NOT NULL | NULL IS NULL | NULL IS NOT NULL |
+-----------+---------------+--------------+------------------+
|         0 |             1 |            1 |                0 |
+-----------+---------------+--------------+------------------+
1 row in set (0.00 sec)

Jak widać, 5 nie jest nieznana, wartość 3 jest także. NULL to oczywiście NULL.

Ok, jak ma się NULL do wartości pustych?

mysql> SELECT 0 IS NULL, 0 IS NOT NULL, '' IS NULL, '' IS NOT NULL;
+-----------+---------------+------------+----------------+
| 0 IS NULL | 0 IS NOT NULL | '' IS NULL | '' IS NOT NULL |
+-----------+---------------+------------+----------------+
|         0 |             1 |          0 |              1 |
+-----------+---------------+------------+----------------+
1 row in set (0,00 sec)

Jak widać, zarówno wartość zero jak i pusty string nie są NULL. W końcu znamy ich wartość – zero i nic. To oczywiście przekłada się na obostrzenia NOT NULL dla danej kolumny. Zakładamy taką tabelę:

mysql> SHOW CREATE TABLE tab_not_null\G

*************************** 1. row ***************************
Table: tab_not_null
Create Table: CREATE TABLE `tab_not_null` (
`a` int(10) NOT NULL,
`b` varchar(10) COLLATE utf8_polish_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci
1 row in set (0.00 sec)

Próbujemy wykonać INSERTy:

mysql> INSERT INTO tab_not_null VALUES (0,'');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO tab_not_null (a) VALUES (0);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> SHOW WARNINGS;
+---------+------+----------------------------------------+
| Level   | Code | Message                                |
+---------+------+----------------------------------------+
| Warning | 1364 | Field 'b' doesn't have a default value |
+---------+------+----------------------------------------+
1 row in set (0.00 sec)

Pierwszy oczywiście wykonuje się poprawnie, w końcu 0 i ‘’ nie są NULL. Drugi INSERT dodaje rekord z wartością zdefiniowaną tylko dla kolumny ‘a’. MySQL zgłasza to w warningu, ale wartość dla kolumny b ustawia na wartość pustą i INSERT jest wykonany. W efekcie zawartość tabeli wygląda następująco:

mysql> SELECT * FROM tab_not_null;
+---+---+
| a | b |
+---+---+
| 0 |   |
| 0 |   |
+---+---+
2 rows in set (0.00 sec)

NULL może być ustawione także jako wartość domyślna dla kolumny. Załóżmy taką tabelę:

mysql> SHOW CREATE TABLE tab_null\G

*************************** 1. row ***************************

Table: tab_null
Create Table: CREATE TABLE `tab_null` (
`a` int(10) DEFAULT NULL,
`b` varchar(10) COLLATE utf8_polish_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_polish_ci
1 row in set (0.00 sec)

W tej sytuacji wynik tych samych INSERTów co poprzednio wyglądać będzie następująco:

mysql> INSERT INTO tab_null VALUES (0,'');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO tab_null (a) VALUES (0);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM tab_null;
+------+------+
| a    | b    |
+------+------+
|    0 |      |
|    0 | NULL |
+------+------+
2 rows in set (0.00 sec)

Wartość domyślna jest ustawiona, więc ostrzeżenie się nie pojawia – za to kolumna ‘b’ przyjmuje wartość domyślną NULL. Oczywiście, możemy także samodzielnie dodać rekord z wartościami NULL:

mysql> INSERT INTO tab_null VALUES (NULL, NULL);
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM tab_null;
+------+------+
| a    | b    |
+------+------+
|    0 |      |
|    0 | NULL |
| NULL | NULL |
+------+------+
3 rows in set (0.00 sec)

Jak sobie zobrazować różnicę pomiędzy NULL a pustą wartością? Dajmy na to adres email. Jeśli wartość kolumny ‘email’ w danym rekordzie jest pusta, oznacza to tyle, że np. dany użytkownik nie posiada adresu email. Jeśli wartość kolumny ‘email’ to NULL, oznaczałoby to że nie wiemy czy dany użytkownik posiada adres email.

Na ten post to tyle, druga część pojawi się w przeciągu kilku dni.