Trong bài này
Cô Mai chuẩn bị lịch gặp người hướng dẫn cho học viên. Một vài bạn chưa có thông tin người hướng dẫn, nên danh sách liên hệ cần tách nhóm này ra. Nếu chỉ tìm những tên khác Cô Mai, cô có thể bỏ sót chính những bạn đang cần được phân công. Bạn cần phân biệt thông tin chưa biết với một giá trị đã biết là khác.
Thông tin thiếu khác với một giá trị đã biết
Trong bảng học viên, mentor lưu tên người hướng dẫn. Hãy đọc tên học viên cạnh thông tin đó trước khi viết bộ lọc. Bạn sẽ thấy có ô chứa tên và có ô chưa có giá trị:
Dữ liệu đầu vào
students6 dòng| id | name | mentor |
|---|---|---|
| 1 | An | Cô Mai |
| 2 | Bình | NULL |
| 3 | Chi | Thầy Nam |
| 4 | Dung | NULL |
| 5 | Huy | Cô Mai |
| 6 | Lan | Thầy Nam |
Câu lệnh
SELECT id, name, mentor
FROM students;Kết quả
| id | name | mentor |
|---|---|---|
| 1 | An | Cô Mai |
| 2 | Bình | NULL |
| 3 | Chi | Thầy Nam |
| 4 | Dung | NULL |
| 5 | Huy | Cô Mai |
| 6 | Lan | Thầy Nam |
NULL là dấu hiệu cho biết ô chưa có giá trị hoặc thông tin chưa biết. NULL không cho biết vì sao thông tin thiếu. Có thể việc phân công chưa xong, hoặc người nhập chưa ghi nhận kết quả phân công.
Bạn có thể kết luận rằng bảng chưa lưu tên người hướng dẫn của Bình và Dung. Bạn chưa thể kết luận hai bạn sẽ không bao giờ có người hướng dẫn. Cũng không nên tự điền tên một giáo viên chỉ để báo cáo trông đầy đủ.
| Cách biểu diễn | Ý nghĩa |
|---|---|
NULL | Chưa có giá trị trong ô |
0 | Một số đã biết, có giá trị bằng không |
'' | Một chuỗi đã có giá trị nhưng không có ký tự |
'NULL' | Văn bản gồm bốn chữ N, U, L, L |
Một chuỗi rỗng (empty string) là chuỗi có độ dài bằng không. Nó khác với việc chưa có giá trị. Để thấy sự khác biệt, riêng ví dụ tiếp theo dùng bản sao dữ liệu với mentor của Dung được đặt thành chuỗi rỗng.
Bạn đọc lại hai dòng cần đối chiếu trên bản sao đó:
Dữ liệu đầu vào
students6 dòng| id | name | mentor |
|---|---|---|
| 1 | An | Cô Mai |
| 2 | Bình | NULL |
| 3 | Chi | Thầy Nam |
| 4 | Dung | |
| 5 | Huy | Cô Mai |
| 6 | Lan | Thầy Nam |
Câu lệnh
SELECT id, name, mentor
FROM students
WHERE id IN (2, 4);Kết quả
| id | name | mentor |
|---|---|---|
| 2 | Bình | NULL |
| 4 | Dung |
Ô của Bình vẫn mang dấu hiệu NULL, còn ô của Dung là một giá trị chữ rỗng. Với người đọc, cả hai ô đều không có tên. Nhưng với SQL, đó là hai thứ khác nhau. Vì vậy, câu hỏi nghiệp vụ và cách kiểm tra dữ liệu cần được nói rõ.
Các ví dụ khác trong bài vẫn dùng dữ liệu gốc, trong đó mentor của cả Bình và Dung là NULL. Việc thử chuỗi rỗng không làm thay đổi các ví dụ khác.
Kiểm tra trực tiếp bằng IS NULL
Muốn tìm các ô thiếu giá trị, bạn dùng IS NULL. Đây là phép kiểm tra trạng thái có giá trị hay chưa, không phải so sánh với một tên giáo viên. Câu sau tìm danh sách cần được kiểm tra việc phân công:
Dữ liệu đầu vào
studentsgiữ 2/6 dòng| id | name | mentor |
|---|---|---|
| 1 | An | Cô Mai |
| 2 | Bình | NULL |
| 3 | Chi | Thầy Nam |
| 4 | Dung | NULL |
| 5 | Huy | Cô Mai |
| 6 | Lan | Thầy Nam |
Câu lệnh
SELECT id, name
FROM students
WHERE mentor IS NULL;Kết quả
| id | name |
|---|---|
| 2 | Bình |
| 4 | Dung |
Kết quả có Bình và Dung. Hãy so từng mã với bảng nguồn: cả hai ô mentor đều là NULL. Bạn đã kiểm tra đúng ô cần biết, không dựa vào số xu hoặc tên của học viên.
Ngược lại, IS NOT NULL giữ những ô đã có giá trị. Bạn dùng nó để lấy danh sách có thông tin người hướng dẫn:
Dữ liệu đầu vào
studentsgiữ 4/6 dòng| id | name | mentor |
|---|---|---|
| 1 | An | Cô Mai |
| 2 | Bình | NULL |
| 3 | Chi | Thầy Nam |
| 4 | Dung | NULL |
| 5 | Huy | Cô Mai |
| 6 | Lan | Thầy Nam |
Câu lệnh
SELECT id, name, mentor
FROM students
WHERE mentor IS NOT NULL;Kết quả
| id | name | mentor |
|---|---|---|
| 1 | An | Cô Mai |
| 3 | Chi | Thầy Nam |
| 5 | Huy | Cô Mai |
| 6 | Lan | Thầy Nam |
Bốn học viên xuất hiện với tên người hướng dẫn tương ứng. Bình và Dung không bị xóa; họ thuộc nhóm thiếu thông tin nên không nằm trong kết quả này. Hai bộ lọc giúp tách nhóm có giá trị và nhóm chưa có giá trị.
| Nhu cầu | Điều kiện |
|---|---|
| Kiểm tra ô chưa có giá trị | mentor IS NULL |
| Kiểm tra ô đã có giá trị | mentor IS NOT NULL |
| Tìm tên giáo viên đúng bằng một chữ cụ thể | mentor = 'Cô Mai' |
Đã có giá trị không đồng nghĩa với đã có một tên hợp lệ. Trên bản sao có chuỗi rỗng, Dung vẫn qua kiểm tra IS NOT NULL. Bạn thử để thấy ranh giới của phép kiểm tra:
Dữ liệu đầu vào
students6 dòng| id | name | mentor |
|---|---|---|
| 1 | An | Cô Mai |
| 2 | Bình | NULL |
| 3 | Chi | Thầy Nam |
| 4 | Dung | |
| 5 | Huy | Cô Mai |
| 6 | Lan | Thầy Nam |
Câu lệnh
SELECT id, name, mentor
FROM students
WHERE id IN (2, 4) AND mentor IS NOT NULL;Kết quả
| id | name | mentor |
|---|---|---|
| 4 | Dung |
Chỉ Dung được giữ trong hai người đang xét. Nếu công việc còn yêu cầu tên phải có chữ, bạn cần quy tắc kiểm tra khác. IS NOT NULL chỉ trả lời về trạng thái có giá trị, nên đừng gán cho nó nhiệm vụ kiểm chất lượng tên.
WHERE chỉ nhận điều kiện đúng
Giả sử bạn hỏi: người hướng dẫn của Bình có phải Cô Mai không? Bảng chưa có tên, nên bạn chưa đủ thông tin để trả lời đúng hoặc sai. SQL cũng giữ sự chưa biết đó khi thực hiện phép so sánh thông thường.
Lôgic ba giá trị (three-valued logic) phân biệt đúng, sai và chưa biết. Trong kết quả biểu thức SQLite, đúng thường hiện là 1, sai là 0 và chưa biết là NULL. Bạn có thể đọc cả biểu thức so sánh như một cột để quan sát:
Dữ liệu đầu vào
students6 dòng| id | name | mentor |
|---|---|---|
| 1 | An | Cô Mai |
| 2 | Bình | NULL |
| 3 | Chi | Thầy Nam |
| 4 | Dung | NULL |
| 5 | Huy | Cô Mai |
| 6 | Lan | Thầy Nam |
Câu lệnh
SELECT name, mentor, mentor = 'Cô Mai' AS matches
FROM students;Kết quả
| name | mentor | matches |
|---|---|---|
| An | Cô Mai | 1 |
| Bình | NULL | NULL |
| Chi | Thầy Nam | 0 |
| Dung | NULL | NULL |
| Huy | Cô Mai | 1 |
| Lan | Thầy Nam | 0 |
An và Huy có matches bằng 1 vì tên được lưu là Cô Mai. Chi và Lan có 0 vì đã biết tên khác. Bình và Dung có NULL vì chưa có tên để so sánh.
Đọc ôLấy giá trị cần kiểmSo sánhCó thể đúng, sai, chưa biếtWHEREChỉ giữ khi đúng
Nhiều bạn viết mentor = NULL. Câu lệnh chạy được nhưng không trả dòng nào:
Dữ liệu đầu vào
students6 dòng| id | name | mentor |
|---|---|---|
| 1 | An | Cô Mai |
| 2 | Bình | NULL |
| 3 | Chi | Thầy Nam |
| 4 | Dung | NULL |
| 5 | Huy | Cô Mai |
| 6 | Lan | Thầy Nam |
Câu lệnh
SELECT id, name
FROM students
WHERE mentor = NULL;Kết quả
| id | name |
|---|---|
| Không có dòng nào | |
Kết quả không có dòng. So sánh bằng với NULL cho kết quả chưa biết, kể cả khi ô nguồn cũng là NULL. Cách sửa là dùng IS NULL, không phải đặt thêm nháy đơn quanh chữ NULL.
Một lỗi khác là coi “khác Cô Mai” bao gồm mọi người chưa có giáo viên. Hãy đọc kết quả của phép so sánh khác:
Dữ liệu đầu vào
students6 dòng| id | name | mentor |
|---|---|---|
| 1 | An | Cô Mai |
| 2 | Bình | NULL |
| 3 | Chi | Thầy Nam |
| 4 | Dung | NULL |
| 5 | Huy | Cô Mai |
| 6 | Lan | Thầy Nam |
Câu lệnh
SELECT id, name
FROM students
WHERE mentor <> 'Cô Mai';Kết quả
| id | name |
|---|---|
| 3 | Chi |
| 6 | Lan |
Chi và Lan được giữ vì có tên Thầy Nam. Bình và Dung vẫn bị loại vì chưa biết họ có khác Cô Mai hay không. Viết NOT (mentor = 'Cô Mai') cũng không biến điều chưa biết thành điều đúng.
Bạn ghép hai nhóm cần lấy bằng OR như sau:
Dữ liệu đầu vào
studentsgiữ 4/6 dòng| id | name | mentor |
|---|---|---|
| 1 | An | Cô Mai |
| 2 | Bình | NULL |
| 3 | Chi | Thầy Nam |
| 4 | Dung | NULL |
| 5 | Huy | Cô Mai |
| 6 | Lan | Thầy Nam |
Câu lệnh
SELECT id, name, mentor
FROM students
WHERE mentor <> 'Cô Mai' OR mentor IS NULL;Kết quả
| id | name | mentor |
|---|---|---|
| 2 | Bình | NULL |
| 3 | Chi | Thầy Nam |
| 4 | Dung | NULL |
| 6 | Lan | Thầy Nam |
Báo cáo giờ có Bình, Chi, Dung và Lan. Nó trả lời một câu hỏi rộng hơn phép so sánh khác đơn lẻ. Hãy xác định việc có nhận người thiếu thông tin hay không trước khi chọn bộ lọc.
Tạo nhãn hiển thị bằng COALESCE
Trên bản in, dấu NULL có thể khó hiểu với phụ huynh. Bạn muốn hiện chữ “Chưa phân công” thay cho ô thiếu. Hàm (function) nhận các giá trị đầu vào và trả một giá trị kết quả; COALESCE chọn giá trị đầu tiên khác NULL.
Đặt cột gốc cạnh nhãn báo cáo để kiểm tra điều gì đã thay đổi:
Dữ liệu đầu vào
students6 dòng| id | name | mentor |
|---|---|---|
| 1 | An | Cô Mai |
| 2 | Bình | NULL |
| 3 | Chi | Thầy Nam |
| 4 | Dung | NULL |
| 5 | Huy | Cô Mai |
| 6 | Lan | Thầy Nam |
Câu lệnh
SELECT name, mentor,
COALESCE(mentor, 'Chưa phân công') AS teacher
FROM students;Kết quả
| name | mentor | teacher |
|---|---|---|
| An | Cô Mai | Cô Mai |
| Bình | NULL | Chưa phân công |
| Chi | Thầy Nam | Thầy Nam |
| Dung | NULL | Chưa phân công |
| Huy | Cô Mai | Cô Mai |
| Lan | Thầy Nam | Thầy Nam |
Trong dòng của Bình, mentor vẫn là NULL còn teacher mang nhãn thay thế. Với An, hàm chọn Cô Mai vì giá trị đầu tiên đã khác NULL. Cột teacher phục vụ trình bày, không phải thông tin mới đã ghi vào hồ sơ.
Hàm xét các đối số từ trái sang phải. Nếu bạn đặt nhãn cố định trước, nhãn đó đã khác NULL và sẽ được chọn cho mọi người. Hãy giữ giá trị muốn ưu tiên ở vị trí đầu tiên.
| Cách gọi | Ý nghĩa |
|---|---|
COALESCE(mentor, 'Chưa phân công') | Ưu tiên tên thật, rồi mới dùng nhãn |
COALESCE('Chưa phân công', mentor) | Luôn chọn nhãn đầu tiên |
COALESCE(NULL, 0) | Chọn số 0 vì đối số đầu thiếu giá trị |
Chuỗi rỗng cũng khác NULL, nên COALESCE không thay nó. Hãy kiểm tra lại bản sao riêng có mentor của Dung là chuỗi rỗng:
Dữ liệu đầu vào
students6 dòng| id | name | mentor |
|---|---|---|
| 1 | An | Cô Mai |
| 2 | Bình | NULL |
| 3 | Chi | Thầy Nam |
| 4 | Dung | |
| 5 | Huy | Cô Mai |
| 6 | Lan | Thầy Nam |
Câu lệnh
SELECT name, COALESCE(mentor, 'Chưa phân công') AS teacher
FROM students
WHERE id IN (2, 4);Kết quả
| name | teacher |
|---|---|
| Bình | Chưa phân công |
| Dung |
Bình nhận nhãn thay thế, Dung thì không. Nếu mục tiêu là làm sạch tên rỗng, bạn cần một bước xử lý riêng. Không nên mô tả COALESCE là công cụ thay mọi nội dung trông giống ô trống.
Với số, phép tính có giá trị chưa biết thường vẫn cho kết quả chưa biết. Hãy xem điều gì xảy ra khi cộng 10 với NULL, với 0 và với giá trị được COALESCE thay bằng 0:
Dữ liệu đầu vào
students6 dòng| id | name |
|---|---|
| 1 | An |
| 2 | Bình |
| 3 | Chi |
| 4 | Dung |
| 5 | Huy |
| 6 | Lan |
Câu lệnh
SELECT name, NULL + 10 AS unknown_result,
0 + 10 AS known_result,
COALESCE(NULL, 0) + 10 AS replaced_result
FROM students
WHERE id = 1;Kết quả
| name | unknown_result | known_result | replaced_result |
|---|---|---|---|
| An | NULL | 10 | 10 |
unknown_result thiếu giá trị, còn hai cột sau có 10. Đó là ba phép tính minh họa, không phải ba số dư của An. Việc thay thiếu bằng 0 đã tạo ra một giả định mới cho phép tính.
Lỗi thường gặp
| Lỗi | Vì sao sai | Cách sửa |
|---|---|---|
Viết mentor = NULL | So sánh cho kết quả chưa biết | Dùng mentor IS NULL |
Viết mentor = 'NULL' để tìm ô thiếu | Nháy đơn tạo một tên chữ cụ thể | Dùng từ khóa NULL trong phép IS |
Cho rằng <> giữ cả người thiếu tên | Điều kiện chưa biết không qua WHERE | Thêm OR mentor IS NULL nếu cần |
Mong COALESCE thay cả chuỗi rỗng | Chuỗi rỗng đã là giá trị khác NULL | Phân biệt ô thiếu với chữ rỗng trước khi xử lý |
Tóm tắt
NULLcho biết ô chưa có giá trị. Nó khác số 0, chữ rỗng và văn bản'NULL'.- Dùng
IS NULLvàIS NOT NULLđể kiểm tra sự có mặt của giá trị. WHEREchỉ giữ điều kiện đúng, nên phép so sánh chưa biết không giúp lấy dòng thiếu thông tin.COALESCEchọn giá trị đầu tiên khácNULLcho kết quả đọc. Nó không sửa hồ sơ nguồn.
Kiểm tra nhanh
Đọc thêm
- SQLite: biểu thức và cách xử lý
NULL— đối chiếu phép so sánh thông thường vớiIS. - SQLite: hàm
COALESCE— xem quy tắc chọn đối số đầu tiên có giá trị.