Null in SQL
Nói zìa mấy thứ linh tinh liên quan tới NULL
trong SQL.
Lược dịch + thêm ví dụ từ https://mitchum.blog
1. NULL
CREATE TABLE `t` (
`a` varchar(10) DEFAULT NULL,
`b` varchar(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO t(a) VALUES ('1');
INSERT INTO t(b) VALUES ('2');
INSERT INTO t VALUES ();
Câu hỏi là nếu có 2 truy vấn như sau thì nên sử dụng truy vấn nào?
SELECT * FROM t WHERE b = NULL;
và
SELECT * FROM t WHERE b IS NULL;
Câu trả lời cuối cùng là nên dùng IS
, sách mô tả như sau:
In SQL, NULL represents the concept of “unknown”
So sánh sự khác biệt giữa NULL và empty value, dữ liệu thể hiện như sau:
INSERT INTO t VALUES ('', '');
SELECT * FROM t;'
+------+------+
| a | b |
+------+------+
| 1 | NULL |
| NULL | 2 |
| NULL | NULL |
| | |
+------+------+
4 rows in set (0.00 sec)
3. Unknown?
Biểu thức WHERE 1 = 1
trả về giá trị là true
, truy vấn sẽ trả về toàn bộ dữ liệu của bảng.
SELECT * FROM t WHERE 1 = 1;
Biểu thức WHERE 1 = 0
trả về giá trị là false
, nghĩa là truy vấn sẽ không trả về bất kỳ dữ liệu nào.
SELECT * FROM t WHERE 1 = 0;
Còn nếu có biểu thức WHERE 1 = NULL
thì do không biết kết quả của phép so sánh là gì, nên truy vấn cũng không trả về bất cứ dữ liệu gì.
SELECT * FROM t WHERE 1 = NULL;
Còn nếu điều kiện là NULL
thì cũng không trả về bất cứ dữ liệu gì.
SELECT * FROM t WHERE NULL;
Túm lại thì:
- Biểu thức sau
WHERE
màtrue
thì trả về dữ liệu. - Biểu thức sau
WHERE
màfalse
thì không trả về dữ liệu. - Hoặc trả về
NULL
hoặcunknown
thì cũng không trả về dữ liệu.
Câu hỏi tiếp theo là database xử lý 2 trường hợp false
và NULL
như nhau thì tại sao phải quan tâm? Tiếp theo thử thêm điều kiện NOT()
.
SELECT * FROM t WHERE NOT(1 = 0);
SELECT * FROM t WHERE NOT(1 = 1);
NOT(false) = true
, trả về dữ liệu.NOT(true) = false
, không trả về dữ liệu.
Nhưng nếu WHERE NOT(1 = NULL)
thì database không trả về true
, cũng không trả về false
mà trả về một NULL
khác ?? 🥺 ?? (đại khái là một NULL khác, khác với cái NULL trước mặc dù đều là NULL =))))))))))
Túm lại thì 2 truy vấn sau trả về kết quả giống y chang nhau, dù điều kiện đối lập nhau.
SELECT * FROM t WHERE 1 = NULL;
SELECT * FROM t WHERE NOT(1 = NULL);
3. NULL and NOT IN
Có điều kiện với IN
là WHERE 1 IN (1, 2, 3, 4, NULL)
, kết quả của biểu thức là true
vì số 1 có tồn tại trong danh sách => trả về dữ liệu của bảng.
SELECT * FROM t WHERE 1 IN (1, 2, 3, 4, NULL);
Nếu điều kiện WHERE 1 NOT IN (1, 2, 3, 4, NULL)
, kết quả của biểu thức sẽ là false
như bình thường vì số 1 có tồn tại trong danh sách.
SELECT * FROM t WHERE 1 NOT IN (1, 2, 3, 4, NULL);
Nhưng vấn đề là nếu với điều kiện 5 NOT IN (1, 2, 3, 4, NULL)
cũng sẽ không trả về dữ liệu của bảng, dù số 5 không tồn tại trong danh sách.
SELECT * FROM t WHERE 5 NOT IN (1, 2, 3, 4 NULL);
Postgres wiki cũng có nói tới trường hợp tương tự, họ khuyến cáo là không nên sử dụng NOT IN
hoặc bất kỳ truy vấn nào kết hợp của NOT
và IN
ví dụ NOT (x IN (SELECT ...))
.
Ngoài ra Markus Winand có một danh sách cách chủ đề chuyên sâu liên quan đến NULL trong SQL có thể tham khảo ở https://modern-sql.com/concept/null hoặc https://modern-sql.com/concept/three-valued-logic.