aedev.net
  • Trang chủ
  • AI
  • Mobile
  • Flutter
  • React Native
  • Backend
  • DevOps
  • Hướng dẫn
No Result
View All Result
SAVED POSTS
aedev.net
  • Trang chủ
  • AI
  • Mobile
  • Flutter
  • React Native
  • Backend
  • DevOps
  • Hướng dẫn
No Result
View All Result
aedev.net
No Result
View All Result
Minh họa kiến trúc backend API gọn gàng cho sản phẩm nhỏ

SQL NOT IN gặp NULL: vì sao truy vấn loại trừ trả về rỗng?

Suong Nguyen by Suong Nguyen
25/10/2026
in Backend
0
585
SHARES
3.2k
VIEWS
Summarize with ChatGPTShare to Facebook

Bạn cần lấy những tài khoản không nằm trong danh sách bị chặn. Dữ liệu có ba tài khoản nhưng truy vấn NOT IN không trả hàng nào. Sau khi kiểm tra, danh sách chặn có thêm một giá trị NULL. Đây là tình huống cần hiểu ngữ nghĩa SQL trước khi nghĩ đến index hay cache.

Bài đối chiếu PostgreSQL 17 và tài liệu SQLite ngày 25/10/2026. Fixture SQL được chạy trên SQLite CLI 3.54.0; chưa chạy PostgreSQL trong lượt biên tập. Phần PostgreSQL dựa trên tài liệu chính thức, không phải kết quả thực thi PostgreSQL được suy ra từ SQLite.

1. Tạo tình huống có thể quan sát

Chạy trong database thử và cùng một phiên kết nối. Hai bảng tạm này chỉ dùng cho bài học; không dùng tên bảng nghiệp vụ thật.

CREATE TEMP TABLE demo_accounts (id integer PRIMARY KEY);
CREATE TEMP TABLE demo_blocked (account_id integer);

INSERT INTO demo_accounts (id) VALUES (1), (2), (3);
INSERT INTO demo_blocked (account_id) VALUES (2), (NULL);

SELECT id
FROM demo_accounts
WHERE id NOT IN (SELECT account_id FROM demo_blocked)
ORDER BY id;

Trên fixture SQLite đã chạy, SELECT cuối không trả hàng nào. Nếu bạn chỉ nhìn hai tài khoản 1 và 3 không khớp giá trị 2 rồi kỳ vọng cả hai xuất hiện, bạn đã bỏ qua hàng NULL trong phía bên phải.

Theo PostgreSQL về subquery expressions, khi không tìm thấy giá trị bằng nhau nhưng phía phải có NULL, NOT IN có thể cho kết quả NULL thay vì true. Giá trị đó không được giữ lại như một điều kiện WHERE đúng. Bảng chân trị trong SQLite SQL expressions cũng mô tả trường hợp này.

2. Diễn đạt điều kiện không tồn tại hàng khớp

Nếu nghiệp vụ là “không có hàng chặn nào bằng ID tài khoản”, hãy viết rõ phép đối chiếu trong subquery:

SELECT a.id
FROM demo_accounts AS a
WHERE NOT EXISTS (
    SELECT 1
    FROM demo_blocked AS b
    WHERE b.account_id = a.id
)
ORDER BY a.id;

Với fixture trên, kết quả đã kiểm tra là 1 và 3. EXISTS xét việc subquery có trả hàng hay không. Hàng chặn có account_id bằng NULL không tạo ra phép bằng true với ID 1 hoặc 3, nên không trở thành một hàng khớp trong subquery.

Số 1 trong SELECT 1 thể hiện rằng ta cần sự tồn tại của hàng, không cần lấy giá trị cụ thể từ hàng đó. Đừng thêm hàm có side effect vào subquery để theo dõi “mỗi hàng đã chạy bao nhiêu lần”; đây không phải hợp đồng thực thi mà EXISTS hứa cung cấp.

3. Khi lọc NULL khỏi phía phải là đúng ý định

Bạn cũng có thể giữ NOT IN và loại những giá trị chưa có ID:

SELECT id
FROM demo_accounts
WHERE id NOT IN (
    SELECT account_id
    FROM demo_blocked
    WHERE account_id IS NOT NULL
)
ORDER BY id;

Fixture này cũng trả 1 và 3. Tuy nhiên, cách sửa cần gắn với ý nghĩa dữ liệu: NULL trong bảng chặn là bản ghi nhập dở, dữ liệu không hợp lệ hay một trạng thái nghiệp vụ có chủ đích? Nếu nó không được phép tồn tại, chỉ lọc khi SELECT có thể làm lỗi chất lượng dữ liệu tiếp tục bị che đi.

Tài liệu comparison operators của PostgreSQL mô tả IS NULL và IS NOT NULL. Đừng viết account_id <> NULL để lọc; đó không phải phép kiểm tra NULL mà bạn đang cần.

4. Rà cả cột bên trái

Trong fixture, ID tài khoản là khóa chính và các giá trị mẫu đều có ID. Nếu cột bên trái có thể NULL, NOT IN và NOT EXISTS với phép bằng không mặc nhiên thể hiện cùng một chính sách cho hàng đó. Trước khi thay toàn bộ truy vấn trong codebase, hãy quyết định bản ghi không có ID phải bị loại, được giữ hay bị xem là dữ liệu lỗi.

Nếu sản phẩm không chấp nhận ID trống, ghi điều kiện a.id IS NOT NULL rõ ràng trong truy vấn dùng trên một cột nullable, đồng thời cân nhắc ràng buộc ở nơi lưu dữ liệu. Không dùng một giá trị thay thế như 0 trong COALESCE chỉ vì nó làm kết quả có vẻ đúng; giá trị thay thế có thể trùng với dữ liệu thật.

Kiểm tra trước khi sửa truy vấn thật

Tạo các ca: bảng chặn rỗng, chỉ có ID hợp lệ, có NULL, có ID lặp và cột trái nullable. Ghi danh sách kết quả mong đợi theo nghiệp vụ rồi mới so sánh SQL. Với ID không nullable trong fixture này, bảng chặn rỗng phải giữ cả ba tài khoản; bảng chỉ chặn 2 phải giữ 1 và 3.

Sau khi đúng ngữ nghĩa, mới đánh giá execution plan trên database và dữ liệu đại diện. Bài này không có benchmark để kết luận NOT EXISTS luôn nhanh hơn NOT IN. Cùng một kết quả logic không đảm bảo cùng một plan trên mọi phiên bản hay phân bố dữ liệu.

Kết luận

NULL khiến điều kiện loại trừ cần được viết và kiểm tra cẩn thận hơn phép so sánh danh sách thông thường. Dùng fixture nhỏ để làm rõ chính sách dữ liệu, rồi chọn NOT EXISTS hoặc NOT IN đã lọc NULL theo đúng ý định. Đừng sửa cú pháp trước khi hiểu những hàng nào thực sự cần được giữ lại.

Nguồn tham khảo

  • PostgreSQL 17: IN, NOT IN và EXISTS
  • PostgreSQL 17: comparison operators và NULL
  • SQLite: IN, NOT IN và EXISTS

Tags: NULLPostgreSQLSQL
SummarizeShare234
Suong Nguyen

Suong Nguyen

Related Stories

Minh họa kiến trúc backend API gọn gàng cho sản phẩm nhỏ

LEFT JOIN và COUNT: đừng đếm khách chưa có đơn thành một đơn hàng

by Suong Nguyen
26/10/2026
0

Phân biệt COUNT(*) và COUNT(cột) trên LEFT JOIN, đặt điều kiện ON đúng mục tiêu và kiểm tra các hàng không có dữ liệu khớp.

Minh họa kiến trúc backend API gọn gàng cho sản phẩm nhỏ

Đọc PostgreSQL EXPLAIN ANALYZE: đừng nhầm cost với mili giây

by Suong Nguyen
24/10/2026
0

Đọc cost, rows, loops và buffers theo đúng ý nghĩa trước khi quyết định thêm index cho truy vấn PostgreSQL.

Minh họa kiến trúc backend API gọn gàng cho sản phẩm nhỏ

Optimistic locking trong PostgreSQL: tránh ghi đè thay đổi của người khác

by Suong Nguyen
23/10/2026
0

Dùng cột version và UPDATE có điều kiện để phát hiện một biểu mẫu đang lưu trên phiên bản dữ liệu đã cũ.

Minh họa kiến trúc backend API gọn gàng cho sản phẩm nhỏ

Idempotency-Key cho API tạo đơn: retry mà không tạo trùng nghiệp vụ

by Suong Nguyen
22/10/2026
0

Thiết kế phạm vi khóa, transaction và response lưu lại để API tạo đơn xử lý an toàn khi client gửi lại request.

Next Post
Minh họa các khái niệm AI, mạng nơ-ron và lập trình trên máy tính

Đánh giá truy hồi RAG bằng Recall@k và MRR trước khi sửa prompt

0 0 votes
Article Rating
Subscribe
Login
Notify of
guest
guest
0 Comments
Oldest
Newest Most Voted
AE Dev

AE Dev mang đến các bài viết về lập trình, mobile app, backend, frontend, WordPress và công nghệ, phù hợp cho developer muốn học hỏi và cập nhật kiến thức thực tế.

Recent Posts

  • React Native Image: cover và contain khác nhau trong cùng một khung ảnh
  • JavaScript sort: vì sao số 10 đứng trước 2 và mảng gốc bị đổi?
  • Android plurals: vì sao getQuantityString cần truyền count hai lần?

Categories

  • AI
  • Backend
  • Đánh giá
  • DevOps
  • Flutter
  • Hướng dẫn
  • Lập trình Mobile
  • Phỏng vấn
  • React Native
  • Uncategorized

Weekly Newsletter

  • Buy JNews
  • Support Forum
  • Pre-sale Question
  • Contact Us

© 2026 AE Dev - Blog công nghệ, lập trình và chia sẻ kiến thức IT.

Welcome Back!

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In
No Result
View All Result
  • Trang chủ
  • AI
  • Mobile
  • React Native
  • Backend
  • DevOps
  • Hướng dẫn
  • Flutter

© 2026 AE Dev - Blog công nghệ, lập trình và chia sẻ kiến thức IT.

wpDiscuz
0
0
Would love your thoughts, please comment.x
()
x
| Reply