CodeGym /Các khóa học /SQL SELF /Ví dụ truy vấn phức tạp với mảng: tổng hợp, lọc, sắp xếp

Ví dụ truy vấn phức tạp với mảng: tổng hợp, lọc, sắp xếp

SQL SELF
Mức độ, Bài học
Có sẵn

Hôm nay tụi mình sẽ tìm hiểu cách tận dụng tối đa mảng trong truy vấn: gom giá trị thành nhóm, lọc theo nội dung và thậm chí sắp xếp ngay trong mảng luôn. Không phải lý thuyết suông đâu — mấy chiêu này gặp hoài trong báo cáo, phân tích, cá nhân hóa và nhiều tình huống thực tế khác. Hiểu nguyên lý là dễ thôi — và giờ tụi mình sẽ làm rõ luôn.

Tổng hợp dữ liệu với mảng

Làm việc với mảng cực kỳ hữu ích khi cần nhóm dữ liệu. Thay vì lấy nhiều dòng — mình gom giá trị cần thiết vào một mảng gọn gàng. Phân tích dễ hơn, kết quả gọn hơn và thường khỏi cần subquery lằng nhằng. Xem thử thực tế nó chạy ra sao nhé.

Ví dụ 1: nhóm dữ liệu thành mảng với array_agg()

Khi bạn muốn gom giá trị từ nhiều dòng trong một nhóm thành mảng, array_agg() là cứu tinh. Đây chắc là function hữu dụng nhất khi xử lý mảng lúc tổng hợp.

-- Mình có bảng students với các trường id, name và course
CREATE TABLE students (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    course VARCHAR(100)
);

-- Thêm vài dòng dữ liệu
INSERT INTO students (name, course) VALUES
('Alysa', 'Toán học'),
('Bob', 'Toán học'),
('Charlie', 'Vật lý'),
('Dave', 'Vật lý'),
('Emma', 'Toán học');

-- Nhóm sinh viên theo khóa học thành mảng
SELECT course, array_agg(name) AS students
FROM students
GROUP BY course;

Kết quả:

course students
Toán học {Alysa, Bob, Emma}
Vật lý {Charlie, Dave}

Nhóm giá trị thành mảng rất tiện nếu bạn muốn trả về dữ liệu ở dạng dễ parse, ví dụ như JSON chẳng hạn.

Ví dụ 2: tạo mảng lồng nhau

Giả sử mình có thêm một bảng nữa và muốn gom dữ liệu từ hai bảng thành mảng? Ví dụ, bảng courses chứa thông tin giảng viên.

-- Tạo bảng giảng viên
CREATE TABLE courses (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    teacher VARCHAR(100)
);

-- Thêm dữ liệu
INSERT INTO courses (name, teacher) VALUES
('Toán học', 'Prof. Min'),
('Vật lý', 'Prof. Peterson');

-- Truy vấn lồng nhau để tạo mảng
SELECT
    c.name AS course_name,
    array_agg(s.name) AS students,
    c.teacher
FROM
    courses c
LEFT JOIN
    students s
ON
    c.name = s.course
GROUP BY
    c.name, c.teacher;

Kết quả:

course_name students teacher
Toán học {Alysa, Bob, Emma} Prof. Min
Vật lý {Charlie, Dave} Prof. Peterson

Giờ mình có bảng cực tiện, show khóa học, giảng viên và sinh viên dưới dạng mảng luôn.

Lọc dữ liệu với mảng

Mảng tự nó đã mạnh rồi, nhưng thực sự bá đạo khi biết lọc dữ liệu dựa trên mảng. Muốn chọn user có từ khóa cụ thể trong danh sách sở thích? Hay đơn hàng mà mỗi giá đều vượt ngưỡng nào đó? Tất cả làm được ngay trong SQL — khỏi cần code thêm ở app.

Ví dụ 1: lọc dòng theo phần tử trong mảng

Giả sử mình muốn tìm tất cả dòng mà mảng chứa giá trị cụ thể, ví dụ tìm sinh viên đăng ký khóa toán học.

-- Lọc sinh viên đăng ký khóa học bằng `ANY`
SELECT *
FROM students
WHERE course = ANY(ARRAY['Toán học', 'Vật lý']);

Ở đây ANY cho phép chỉ định mảng giá trị, và truy vấn trả về dòng mà course khớp ít nhất một giá trị trong mảng.

Ví dụ 2: Kiểm tra giao nhau giữa mảng

Giờ giả sử mình có bảng student_interests, ghi sở thích sinh viên dưới dạng mảng. Mình muốn tìm sinh viên có sở thích trùng với tiêu chí của mình.

-- Tạo bảng sở thích sinh viên
CREATE TABLE student_interests (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    interests TEXT[]
);

-- Thêm dữ liệu
INSERT INTO student_interests (name, interests) VALUES
('Alysa', ARRAY['lap trinh', 'am nhac']),
('Bob', ARRAY['the thao', 'lap trinh']),
('Charlie', ARRAY['doc sach', 'nhiep anh']),
('Emma', ARRAY['am nhac', 'the thao']);

-- Tìm sinh viên quan tâm lap trinh hoặc am nhac
SELECT *
FROM student_interests
WHERE interests && ARRAY['lap trinh', 'am nhac'];

Toán tử && kiểm tra giao nhau giữa hai mảng. Nếu có ít nhất một phần tử bên trái trùng với mảng bên phải, dòng đó được chọn.

Kết quả:

id name interests
1 Alysa {lap trinh, am nhac}
2 Bob {the thao, lap trinh}
4 Emma {am nhac, the thao}

Sắp xếp mảng

Đôi khi thứ tự giá trị trong mảng rất quan trọng — nhất là khi gom mảng từ nhiều dòng hoặc muốn chuẩn bị dữ liệu để hiển thị. PostgreSQL cho phép sắp xếp phần tử ngay trong truy vấn, khỏi cần xử lý thêm.

Ví dụ 1: sắp xếp giá trị trong mảng

Đôi khi cần sắp xếp phần tử trong mảng. Ví dụ, sắp xếp sở thích sinh viên theo alphabet.

-- Sắp xếp phần tử mảng bằng function `array_sort()`
SELECT 
    name,
    array_sort(interests) AS sorted_interests
FROM 
    student_interests;

Kết quả:

name sorted_interests
Alysa {am nhac, lap trinh}
Bob {lap trinh, the thao}
Charlie {doc sach, nhiep anh}
Emma {am nhac, the thao}

Ví dụ 2: sắp xếp dòng theo độ dài mảng

Giờ giả sử mình muốn sắp xếp sinh viên theo số lượng sở thích — từ "đam mê" nhất đến "nhạt" nhất.

-- Sắp xếp dòng theo độ dài mảng
SELECT 
    name, 
    interests, 
    array_length(interests, 1) AS interests_count
FROM 
    student_interests
ORDER BY 
    interests_count DESC;

Kết quả:

name interests interests_count
Alysa {lap trinh, am nhac} 2
Bob {the thao, lap trinh} 2
Charlie {doc sach, nhiep anh} 2
Emma {am nhac, the thao} 2

Dù ví dụ này ai cũng có số sở thích bằng nhau, truy vấn kiểu này có thể chỉnh lại cho bảng lớn hơn.

2
Nhiệm vụ
SQL SELF, mức độ, bài học
Đã khóa
Nhóm giá trị thành mảng
Nhóm giá trị thành mảng
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION