Biểu thức bảng thông thường, viết tắt là CTE, chỉ đơn giản là một kỹ thuật để tạo một tập hợp các bản ghi tạm thời có thể được tham chiếu trong một câu lệnh INSERT, SELECT, UPDATE hoặc DELETE.
Biểu thức bảng phổ biến đã được Microsoft giới thiệu trong SQL Server 2005. Chúng không được lưu trữ dưới dạng đối tượng trong bộ nhớ cơ sở dữ liệu vì tuổi thọ của chúng bằng với thời gian thực thi của truy vấn. Ngay sau khi một truy vấn hoàn thành, chúng sẽ bị xóa khỏi bộ nhớ cơ sở dữ liệu. CTE có thể được tham chiếu trong một truy vấn bao nhiêu lần tùy thích và chúng cũng có thể tự tham chiếu.
Hãy tạo cơ sở dữ liệu với bảng học sinh và chèn một số hồ sơ học sinh giả vào đó. Chúng tôi sẽ sử dụng cơ sở dữ liệu này để viết các truy vấn CTE. Luôn đảm bảo rằng bạn đã được sao lưu tốt trước khi thử nghiệm với một mã mới. Xem bài viết này về sao lưu SQL nếu bạn không chắc chắn.
Thực thi các truy vấn sau trên máy chủ của bạn.
CREATE DATABASE schooldb CREATE TABLE student ( id INT PRIMARY KEY, name VARCHAR(50) NOT NULL, gender VARCHAR(50) NOT NULL, DOB datetime NOT NULL, total_score INT NOT NULL, ) INSERT INTO student VALUES (1, 'Jolly', 'Female', '12-JUN-1989', 500), (2, 'Jon', 'Male', '02-FEB-1974', 545), (3, 'Sara', 'Female', '07-MAR-1988', 600), (4, 'Laura', 'Female', '22-DEC-1981', 400), (5, 'Alan', 'Male', '29-JUL-1993', 500), (6, 'Kate', 'Female', '03-JAN-1985', 500), (7, 'Joseph', 'Male', '09-APR-1982', 643), (8, 'Mice', 'Male', '16-AUG-1974', 543), (9, 'Wise', 'Male', '11-NOV-1987', 499), (10, 'Elis', 'Female', '28-OCT-1990', 400);
Bây giờ, hãy tạo một biểu thức bảng chung rất đơn giản. CTE này sẽ chứa hồ sơ của tất cả các học sinh sinh trước ngày 1 tháng 1 năm 1985. Hãy xem tập lệnh sau.
USE schooldb; WITH OldStudents AS ( SELECT * FROM student WHERE DOB < '1985-01-01' )
Để tạo CTE, bạn phải bắt đầu bằng từ khóa "WITH", sau đó là tên của CTE và từ khóa "AS".
Tiếp theo, trong ngoặc đơn, bạn phải viết truy vấn trả về các bản ghi mà CTE sẽ tạm thời lưu trữ. Trong đoạn mã trên, chúng tôi đã tạo một CTE có tên là “OldStudents”.
Tuy nhiên, lưu ý rằng nếu bạn cố gắng thực hiện truy vấn trên, bạn sẽ gặp lỗi. Điều này là do khi bạn tạo CTE, bạn phải sử dụng nó ngay lập tức.
Hãy chọn tất cả các bản ghi từ CTE “OldStudents” mới được tạo của chúng tôi. Hãy thử tập lệnh sau trên máy chủ của bạn.
USE schooldb; WITH OldStudents AS ( SELECT * FROM student WHERE DOB < '1985-01-01' ) SELECT * FROM OldStudents
Tập lệnh trên sẽ truy xuất tập hợp các bản ghi sau:
Tính Tổng hợp qua CTE
Giống như bảng, bạn có thể thực hiện các chức năng tổng hợp trên CTE. Hãy xem một ví dụ khác về CTE.
USE schooldb; WITH SumofScores AS ( SELECT gender, SUM(total_score) as SumScore FROM student GROUP BY gender ) SELECT AVG (SumScore) FROM SumofScores
Trong ví dụ trên, chúng tôi đã tạo một CTE có tên là SumofScores. CTE này chứa tổng các giá trị được lưu trữ trong cột tổng điểm của bảng sinh viên. Kết quả được nhóm theo cột giới tính. Dữ liệu được lưu trữ bởi CTE trông giống như sau trong bộ nhớ:
Tiếp theo, chúng tôi thực hiện chức năng AVG trên cột "SumScore" của CTE. Kết quả cuối cùng của tập lệnh sẽ là trung bình của 2400 và 2730, tức là 2565.
Điều này phức tạp hơn một chút so với ví dụ trước nhưng thể hiện khái niệm CTE rõ ràng hơn.
Các cột gắn nhãn trong CTE
Trong ví dụ trước, chúng tôi đã thêm bí danh vào cột thứ hai của CTE. Chúng tôi đã đổi tên nó thành “SumScore”. Đây là một cách gắn nhãn cột trong CTE và tương tự như bí danh cột trong bảng.
Tuy nhiên, có một cách khác để xác định tên cột trong CTE. Hãy xem truy vấn sau.
USE schooldb; WITH SumofScores(Gender, SumScore) AS ( SELECT gender, SUM(total_score) FROM student GROUP BY gender ) SELECT AVG (SumScore) From SumofScores
Trong tập lệnh này, chúng tôi đã thêm tên cột của CTE “SumofScores” trong ngoặc đơn sau tên CTE. Mỗi tên cột được phân tách bằng dấu phẩy.
Nếu bạn nhìn vào câu lệnh SELECT sau CTE, bạn có thể thấy rằng sau đó chúng tôi đang tham chiếu đến cột "Điểm tổng" mà chúng tôi đã tạo trong dấu ngoặc đơn sau tên CTE.
Tạo nhiều CTE
Tất cả các ví dụ cho đến nay chỉ sử dụng một biểu thức bảng chung duy nhất cho rõ ràng. Bạn có thể tạo danh sách các CTE cùng một lúc và sau đó sử dụng tất cả chúng kết hợp trong tập kết quả cuối cùng.
Điều này được giải thích tốt nhất với sự trợ giúp của một ví dụ. Hãy xem đoạn mã sau đây.
Ở đây chúng ta sẽ tạo hai CTE. CTE đầu tiên sẽ lưu trữ tất cả hồ sơ của những học sinh sinh trước ngày 1 tháng 1 năm 1985. CTE thứ hai sẽ chứa tất cả hồ sơ của những học sinh sinh vào hoặc sau ngày 1 tháng 1 năm 1985.
Sau đó, chúng tôi sẽ sử dụng các câu lệnh chọn để lấy tất cả các bản ghi từ cả hai CTE. Các bản ghi đã truy xuất sẽ được hợp nhất với nhau bằng cách sử dụng câu lệnh UNION. Cuối cùng, bản ghi đã hợp nhất sẽ được sắp xếp theo thứ tự tăng dần của ngày sinh.
USE schooldb; WITH OldStudents AS ( SELECT * FROM student WHERE DOB < '1985-01-01' ), YoungStudents AS ( SELECT * FROM student WHERE DOB >= '1985-01-01' ) (SELECT * FROM OldStudents UNION SELECT * FROM YoungStudents) ORDER BY DOB
Trong truy vấn SQL ở trên, chúng tôi đã tạo hai CTE:“OldStudents” và “YoungStudents”. Điều đáng nói là bạn không cần phải sử dụng từ khóa “WITH” với mọi CTE. Bạn chỉ được yêu cầu sử dụng nó trước CTE đầu tiên trong tập lệnh, sau đó, bạn có thể tạo bất kỳ số lượng CTE nào bằng cách phân tách chúng bằng dấu phẩy.
Tập lệnh trên truy xuất các kết quả sau: