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 UNION và UNION ALL: đừng làm mất sự kiện khi hợp nhất dữ liệu

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

Hai sự kiện mở màn hình có thể cùng thời điểm và cùng loại, nhưng vẫn là hai lần xảy ra riêng biệt. Nếu hợp nhất log bằng UNION sau khi bỏ cột ID, bạn có thể vô tình biến chúng thành một dòng. Một báo cáo ít dòng hơn chưa chắc đã là dữ liệu được làm sạch đúng.

Bài đối chiếu PostgreSQL 17 và tài liệu SQLite ngày 28/10/2026. Fixture được chạy bằng SQLite CLI 3.54.0 trong database bộ nhớ; chưa chạy trên PostgreSQL hoặc đo hiệu năng. Mục tiêu là chọn đúng ngữ nghĩa trước khi tối ưu truy vấn.

1. Tạo bốn sự kiện có dữ liệu hiển thị trùng nhau

Mở sqlite3 :memory: và chạy các đoạn SQL theo thứ tự trong cùng phiên:

CREATE TABLE web_events (id INTEGER PRIMARY KEY, at TEXT, kind TEXT);
CREATE TABLE mobile_events (id INTEGER PRIMARY KEY, at TEXT, kind TEXT);
INSERT INTO web_events VALUES
  (1, '2026-10-27T08:00:00Z', 'open'),
  (2, '2026-10-27T08:00:00Z', 'open');
INSERT INTO mobile_events VALUES
  (1, '2026-10-27T08:00:00Z', 'open'),
  (2, '2026-10-27T08:01:00Z', 'close');

Mỗi bảng có hai ID khác nhau. ID số 1 ở web và ID số 1 ở mobile thuộc hai nguồn, nên không tự tạo thành một định danh toàn cục. Cột thời gian dạng text ở đây dùng cùng định dạng UTC để fixture dễ đọc; schema production cần kiểu thời gian và ràng buộc phù hợp hệ quản trị.

2. UNION loại trùng ở kết quả đã chiếu cột

SELECT at, kind FROM web_events
UNION
SELECT at, kind FROM mobile_events
ORDER BY at, kind;

Kết quả có hai dòng: một open lúc 08:00 và một close lúc 08:01. Dữ liệu hiển thị của ba sự kiện open giống hệt nhau sau khi chỉ chọn hai cột, nên chúng được gộp thành một.

Đây là hành vi đúng của UNION. Nó không biết ba dòng đại diện cho ba hành động riêng hay ba bản sao của cùng hành động. Ý nghĩa đó phải đến từ hợp đồng dữ liệu và các cột bạn giữ lại.

Nếu yêu cầu là tập các cặp thời điểm–loại duy nhất, kết quả hai dòng có thể chính là điều cần tìm. Nếu yêu cầu là đếm số sự kiện, làm mất số lần xuất hiện trước khi đếm sẽ đổi kết quả nghiệp vụ.

3. Giữ số lần xuất hiện bằng UNION ALL

WITH combined AS (
  SELECT at, kind FROM web_events
  UNION ALL
  SELECT at, kind FROM mobile_events
)
SELECT kind, COUNT(*) AS events
FROM combined
GROUP BY kind
ORDER BY kind;

Kết quả là close = 1 và open = 3. Nếu thay UNION ALL bằng UNION trong CTE, open chỉ còn 1. Cả hai câu SQL đều chạy, nhưng đang trả lời hai câu hỏi khác nhau.

UNION ALL cũng giữ dòng lặp có trong chính một nguồn. Nó không phải một thao tác chống ghi trùng. Khi hệ thống có retry gửi cùng sự kiện nhiều lần, cần một định danh sự kiện và chính sách khử trùng riêng, không chỉ đổi toán tử hợp nhất.

4. Mang theo nguồn và ID khi cần truy vết

SELECT 'web' AS source, id, at, kind FROM web_events
UNION ALL
SELECT 'mobile' AS source, id, at, kind FROM mobile_events
ORDER BY source, id;

Câu này giữ cả bốn sự kiện cùng định danh ghép (source, id). Nó giúp bạn quay lại nguồn khi kiểm tra một dòng báo cáo. Nếu thêm các cột này rồi dùng UNION, tiêu chuẩn “trùng” cũng thay đổi vì toàn bộ hàng kết quả đã khác.

Đừng khử trùng theo vài cột dễ hiển thị chỉ vì chúng giống nhau. Hãy thống nhất khóa nghiệp vụ, cách xử lý event gửi lại và việc hai nguồn có thể cùng mô tả một hành động hay không. Những quyết định đó nằm ngoài khả năng suy luận tự động của UNION.

Kiểm tra hình dạng và thứ tự kết quả

Hai nhánh cần trả cùng số cột, theo vị trí và có kiểu dữ liệu tương thích. Viết danh sách cột rõ ràng giúp tránh phụ thuộc vào SELECT * khi schema của một nguồn thay đổi. Tên cột giống nhau cũng không cứu được việc hai nhánh đặt sai thứ tự cột.

Đặt ORDER BY ở tầng kết quả chung khi cần thứ tự ổn định. Không dựa vào việc nhánh web được viết trước để giả định mọi dòng web luôn xuất hiện trước. Trong ví dụ cuối, thứ tự được nêu trực tiếp bằng source và id.

Lỗi thường gặp và giới hạn

Nếu tổng số sự kiện giảm, kiểm tra phép chiếu cột và toán tử hợp nhất trước khi sửa COUNT. Thử dữ liệu trùng trong một nhánh, trùng giữa hai nhánh và cùng ID ở hai nguồn. Những fixture này bộc lộ khác biệt rõ hơn dữ liệu mà mọi hàng đều duy nhất.

UNION cần xử lý loại trùng trong khi UNION ALL không yêu cầu bước đó theo ngữ nghĩa, nhưng bài chưa đo thời gian hoặc bộ nhớ. Hãy xem execution plan trên dữ liệu thật nếu hiệu năng là vấn đề. Không chọn UNION ALL chỉ vì nghe nói nhanh hơn khi nghiệp vụ thực sự cần một tập duy nhất.

Nguồn tham khảo

  • PostgreSQL 17: Combining queries
  • PostgreSQL 17: SELECT và UNION clause
  • SQLite: Compound SELECT statements

Tags: Data processingPostgreSQLSQL
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 ROW_NUMBER: lấy nguyên bản ghi mới nhất của mỗi khách hàng

by Suong Nguyen
27/10/2026
0

Xếp hạng đơn hàng theo từng khách, xử lý thời điểm trùng nhau và phân biệt lọc trước với lọc sau window function.

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ỏ

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

by Suong Nguyen
25/10/2026
0

Dựng một fixture nhỏ để hiểu NOT IN với NULL, chọn NOT EXISTS theo nghiệp vụ và kiểm tra cả cột bên trái lẫn bên phải.

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.

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

structuredClone hay JSON round-trip: chọn cách sao chép theo kiểu dữ liệu

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 Switch: cập nhật value từ onValueChange và khóa đúng bằng disabled
  • Phỏng vấn JavaScript: vì sao callback trong vòng lặp đều đọc cùng giá trị?
  • Android ClipboardManager: sao chép text và tránh thông báo trùng từ Android 13

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