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ỏ

COUNT DISTINCT và NULL: đếm giá trị khác nhau hay đếm cả nhóm thiếu?

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

Báo cáo có ba loại nguồn đăng ký hiển thị trên giao diện, nhưng truy vấn COUNT(DISTINCT source) chỉ trả về hai. Trước khi thêm một đơn vị vào kết quả, hãy xem nguồn thứ ba có thật sự là một chuỗi hay chỉ là nhãn giao diện dành cho NULL.

Bài này giúp bạn viết rõ hợp đồng của một chỉ số: đếm nguồn đã biết, hay đếm các nhóm kể cả dữ liệu thiếu. Hai câu hỏi hợp lệ nhưng cần hai truy vấn khác nhau.

Điều kiện và phạm vi

Cập nhật 11/11/2026, đối chiếu tài liệu PostgreSQL 17 và SQLite. Các truy vấn bên dưới được chạy bằng SQLite 3.54.0 trên dữ liệu CTE tự tạo, không ghi bảng sản xuất. Chưa chạy PostgreSQL server, ORM hay công cụ BI. Kết quả fixture không chứng minh chi phí thực thi trên bảng lớn.

Theo tài liệu aggregate, COUNT(*) đếm dòng, COUNT(expression) bỏ NULL, còn COUNT(DISTINCT expression) đếm các giá trị khác nhau không phải NULL. Cách đặt alias nên phản ánh đúng điều bạn đang đo.

1. Đặt bốn phép đếm cạnh nhau

Fixture có năm sự kiện: hai từ web, một từ app và hai chưa có nguồn. Chuỗi web lặp lại là cùng một nguồn; NULL biểu diễn giá trị chưa biết trong bài này.

WITH events(source) AS (
  VALUES ('web'), ('web'), ('app'), (NULL), (NULL)
)
SELECT COUNT(*) AS total_rows,
       COUNT(source) AS known_source_rows,
       COUNT(DISTINCT source) AS distinct_known_sources,
       COUNT(*) - COUNT(source) AS missing_source_rows
FROM events;

Kết quả fixture là 5, 3, 2, 2. Ba dòng có nguồn không đồng nghĩa ba nguồn khác nhau. Hai dòng thiếu cũng không làm COUNT(DISTINCT source) tăng lên.

Khi review báo cáo, hãy hỏi một người khác đọc alias mà chưa xem SQL. Nếu họ hiểu distinct_known_sources là số nguồn đã có giá trị, tên đó đã giảm một điểm mơ hồ. Nếu sản phẩm gọi đây là “tổng nhóm nguồn”, cần kiểm tra lại định nghĩa trước khi đưa số lên dashboard.

2. Đếm nhóm, có bao gồm NULL

Giả sử giao diện cần một nhóm “Chưa rõ nguồn”. Có thể lấy các nhóm bằng một truy vấn con, sau đó đếm dòng của kết quả đó.

WITH events(source) AS (
  VALUES ('web'), ('web'), ('app'), (NULL), (NULL)
), source_groups AS (
  SELECT DISTINCT source FROM events
)
SELECT COUNT(*) AS groups_including_missing
FROM source_groups;

Fixture trả về 3. Truy vấn con có web, app và một dòng NULL; lớp ngoài dùng COUNT(*), nên dòng NULL cũng được tính. Không có thao tác đổi NULL thành chuỗi trong dữ liệu gốc.

Để giao diện dễ kiểm tra, bạn có thể tạm xem từng nhóm và số dòng bên trong. Ở fixture này, web có hai dòng, app một dòng, NULL hai dòng. Tổng kích thước các nhóm phải bằng năm. Đây là phép đối chiếu đơn giản giúp phát hiện điều kiện lọc bị đặt sai vị trí.

3. Tránh nhãn giả trùng với dữ liệu thật

Một cách viết ngắn thường gặp là thay NULL bằng một chuỗi rồi đếm distinct. Vấn đề xuất hiện khi chuỗi đó cũng có thể được gửi lên từ hệ thống.

WITH events(source) AS (
  VALUES ('unknown'), (NULL)
)
SELECT COUNT(DISTINCT COALESCE(source, 'unknown')) AS merged_groups,
       (SELECT COUNT(*) FROM (
          SELECT DISTINCT source FROM events
       )) AS separate_groups
FROM events;

Kết quả fixture là 1, 2: nhãn thay thế đã gộp hai trường hợp khác nhau. Nếu hợp đồng sản phẩm chủ ý xem hai trường hợp là một thì kết quả có thể phù hợp; nếu không, cách viết ngắn đã làm mất thông tin.

Kiểm tra trường hợp biên

Thêm ba fixture trước khi dùng cho báo cáo thật: toàn bộ nguồn là NULL, chỉ một nguồn lặp nhiều lần, và tập không có dòng. Với tập rỗng, cả hai phép đếm distinct đã biết và đếm nhóm qua truy vấn con đều bằng 0. Không được cộng 1 vô điều kiện để đại diện cho nhóm thiếu.

Đối với chuỗi, hãy xác định riêng chính sách chữ hoa, khoảng trắng và collation. Bài này chỉ dùng các chuỗi ASCII chính xác; không khẳng định web và WEB sẽ được xem như nhau trên mọi schema. Chuẩn hóa chuỗi là quyết định dữ liệu cần được kiểm thử riêng.

Lỗi thường gặp

Đổi alias nhưng giữ truy vấn cũ không làm thay đổi ý nghĩa phép đếm. Tương tự, hiển thị NULL thành “Khác” trên frontend không tự biến nó thành một giá trị khác NULL trong database.

Với một truy vấn có JOIN, cần kiểm tra số dòng đầu vào trước aggregate. Fixture hiện tại không có JOIN, không có phân trang và không đánh giá index. Nếu số dòng tăng sau JOIN, hãy giải quyết quan hệ đó trước khi dùng DISTINCT để che kết quả bất ngờ.

Kết luận

Đếm giá trị đã biết và đếm nhóm bao gồm dữ liệu thiếu là hai chỉ số riêng. Viết rõ định nghĩa, giữ fixture có NULL, rồi chọn phép đếm tương ứng.

Nguồn tham khảo

  • PostgreSQL 17: Aggregate expressions
  • SQLite: Aggregate functions

Tags: AggregationDatabaseSQL
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ỏ

SQL COALESCE: chuỗi rỗng chưa phải NULL, xử lý bằng NULLIF và TRIM

by Suong Nguyen
10/11/2026
0

Phân biệt NULL, chuỗi rỗng và chuỗi chỉ có dấu cách trước khi chọn giá trị dự phòng cho một trường văn bản.

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

SQL tính tỷ lệ: ép kiểu trước phép chia để không mất phần thập phân

by Suong Nguyen
09/11/2026
0

Kiểm tra phép chia số nguyên, lỗi CAST quá muộn và mẫu số bằng 0 bằng các truy vấn SQLite nhỏ, kèm đối chiếu PostgreSQL 17.

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

COUNT với CASE: vì sao ELSE 0 vẫn đếm cả dòng không khớp?

by Suong Nguyen
08/11/2026
0

Dựng dữ liệu nhỏ để phân biệt COUNT(CASE), SUM(CASE) và FILTER, rồi kiểm tra số đếm khi không có bản ghi.

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

SQL RANK và DENSE_RANK: đồng hạng có làm bỏ số thứ hạng tiếp theo?

by Suong Nguyen
07/11/2026
0

Dùng dữ liệu đồng điểm để chọn RANK, DENSE_RANK hoặc ROW_NUMBER, đồng thời tránh vô tình phá nhóm đồng hạng bằng cột ID.

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: thông báo nội dung đổi cho TalkBack bằng accessibilityLiveRegion
  • Promise.finally: return giá trị mới có thay kết quả của chuỗi không?
  • Android TextUtils.isEmpty không loại chuỗi toàn khoảng trắng

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