Câu trả lời cơ bản
Có CTE (Biểu thức bảng chung) trong Postgres (giống như trong bất kỳ RDBMS hiện đại chính nào ngoại trừ MySQL). Kể từ phiên bản 9.1 bao gồm các CTE sửa đổi dữ liệu. Chúng có thể được "lồng vào nhau".
Cập nhật:MySQL 8.0 cuối cùng đã thêm CTE.
Không giống như truy vấn phụ CTE đặt ra như những rào cản tối ưu hóa. Trình lập kế hoạch truy vấn không thể nội dòng các lệnh tầm thường vào lệnh chính hoặc sắp xếp lại các phép nối giữa các truy vấn chính và CTE. Điều này cũng có thể xảy ra với các truy vấn con. Có thể (rất) tốt hoặc (rất) kém đối với hiệu suất, điều đó phụ thuộc vào.
Dù bằng cách nào, CTE cũng yêu cầu chi phí (chi phí hiệu suất) cao hơn một chút so với truy vấn con.
Cập nhật:Postgres 12 cuối cùng có thể nội tuyến CTE đơn giản trong truy vấn chính.
Chi tiết bạn không yêu cầu
Câu hỏi của bạn rất cơ bản, trên đây chắc cũng đủ trả lời. Nhưng tôi sẽ thêm một chút cho người dùng nâng cao (và một ví dụ mã để hiển thị cú pháp).
Tất cả các CTE của truy vấn đều dựa trên cùng một ảnh chụp nhanh của cơ sở dữ liệu. CTE tiếp theo có thể sử dụng lại đầu ra của các CTE trước đó (bảng tạm thời nội bộ), nhưng ảnh hưởng trên các bảng bên dưới là vô hình đối với các CTE khác. Trình tự của nhiều CTE là tùy ý trừ khi một cái gì đó được trả lại bằng RETURNING
mệnh đề cho INSERT
, UPDATE
, DELETE
- không liên quan cho SELECT
, vì nó không thay đổi bất cứ điều gì và chỉ đọc từ ảnh chụp nhanh.
Điều đó có thể có những tác động tinh tế với nhiều bản cập nhật sẽ ảnh hưởng đến cùng một hàng. Chỉ một cập nhật có thể ảnh hưởng đến từng hàng. Cái nào bị ảnh hưởng bởi chuỗi CTE.
Cố gắng dự đoán kết quả:
CREATE TEMP TABLE t (t_id int, txt text);
INSERT INTO t VALUES (1, 'foo'), (2, 'bar'), (3, 'baz');
WITH sel AS (SELECT * FROM t)
, up1 AS (UPDATE t SET txt = txt || '1' WHERE t_id = 1 RETURNING *)
, up2 AS (UPDATE t SET txt = t.txt || '2'
FROM up1
WHERE up1.t_id = t.t_id
RETURNING t.*)
, ins AS (INSERT INTO t VALUES (4, 'bamm'))
, up3 AS (UPDATE t SET txt = txt || '3' RETURNING *)
SELECT 'sel' AS source, * FROM sel
UNION ALL
SELECT 'up1' AS source, * FROM up1
UNION ALL
SELECT 'up2' AS source, * FROM up2
UNION ALL
SELECT 'up3' AS source, * FROM up3
UNION ALL
SELECT 't' AS source, * FROM t;
SQL Fiddle
Đừng thất vọng, tôi nghi ngờ có nhiều người ở đây có thể đã làm được điều đó. :)
Ý chính của điều này: tránh các lệnh xung đột trong CTE.