Làm thế nào để sử dụng nhiều câu lệnh WITH trong một truy vấn PostgreSQL?


97

Tôi muốn "khai báo" nhiều bảng TEMP hiệu quả bằng cách sử dụng câu lệnh WITH. Truy vấn tôi đang cố gắng thực hiện dọc theo các dòng:

WITH table_1 AS (
SELECT GENERATE_SERIES('2012-06-29', '2012-07-03', '1 day'::INTERVAL) AS date
)

WITH table_2 AS (
SELECT GENERATE_SERIES('2012-06-30', '2012-07-13', '1 day'::INTERVAL) AS date
)

SELECT * FROM table_1
WHERE date IN table_2

Tôi đã đọc tài liệu PostgreSQL và nghiên cứu về việc sử dụng nhiều WITHcâu lệnh và không thể tìm thấy câu trả lời.


Hãy thử một dấu phẩy trước withcâu lệnh thứ hai bất kỳ câu lệnh nào khác sau đó. Không chắc chắn về postgres nhưng đó là cú pháp bình thường với Oracle và máy chủ sql
msheikh25

Tôi đã thử sử dụng dấu phẩy và sau đó là dấu chấm phẩy và vẫn có lỗi cú pháp: ERROR: syntax error at or near "WITH"đối với dấu phẩy và ERROR: syntax error at or near ";"dấu chấm phẩy.
Greg

Câu trả lời:


156

Theo các nhận xét khác, Biểu thức bảng chung thứ hai [CTE] được đặt trước bằng dấu phẩy không phải là câu lệnh WITH vì vậy

WITH cte1 AS (SELECT...)
, cte2 AS (SELECT...)
SELECT *
FROM
    cte1 c1
    INNER JOIN cte2 c2
    ON ........

Về mặt truy vấn thực tế của bạn, cú pháp này sẽ hoạt động trong PostgreSql, Oracle và sql-server, về sau, bạn thường sẽ tiếp tục WITHvới dấu chấm phẩy ( ;WTIH), nhưng đó là bởi vì thông thường sql-server folks (tôi bao gồm) không kết thúc các câu lệnh trước đó cần được kết thúc trước khi CTE được xác định ...

Tuy nhiên, lưu ý rằng bạn đã gặp vấn đề cú pháp thứ hai liên quan đến WHEREcâu lệnh của mình . WHERE date IN table_2không hợp lệ vì bạn không bao giờ thực sự tham chiếu một giá trị / cột từ bảng_2. Tôi thích INNER JOINhơn INhoặc Existshơn đây là một cú pháp nên hoạt động với JOIN:

WITH table_1 AS (
SELECT GENERATE_SERIES('2012-06-29', '2012-07-03', '1 day'::INTERVAL) AS date
)

, table_2 AS (
SELECT GENERATE_SERIES('2012-06-30', '2012-07-13', '1 day'::INTERVAL) AS date
)

SELECT * 
FROM
     table_1 t1
     INNER JOIN 
     table_2 t2
     ON t1.date = t2.date
;

Nếu bạn muốn giữ theo cách bạn đã có, thường là EXISTS sẽ tốt hơn IN nhưng để sử dụng IN, bạn cần một câu lệnh SELECT thực tế trong where của bạn.

SELECT * 
FROM
     table_1 t1
WHERE t1.date IN (SELECT date FROM table_2);

IN rất có vấn đề khi datecó thể xảy ra NULLvì vậy nếu bạn không muốn sử dụng JOINthì tôi sẽ đề xuất EXISTS. Như sau:

SELECT * 
FROM
     table_1 t1
WHERE EXISTS (SELECT * FROM table_2 t2 WHERE t2.date = t1.date);

2
Cảm ơn bạn đã giải thích trong chiều sâu, cú pháp làm việc :)
Greg

rất vui được giúp đỡ. Tôi không thể tìm thấy bài viết về việc không sử dụng IN nhưng tôi thực sự khuyên bạn nên sử dụng THAM GIA hoặc TỒN TẠI trên IN. Nếu giá trị null tồn tại trong tập kết quả của bạn, điều gì xảy ra là bạn sẽ nhận được mọi bản ghi không chỉ những bản ghi bạn muốn. Thật kỳ lạ nhưng đó là cách hoạt động của hầu hết các RDBM. hãy thử kiểm tra một tìm kiếm trên nó, tôi biết tốt câu trả lời tôi đã thấy chuyện đó là trên trang web này quá ... dù sao, có một đêm ngon giấc
Matt

5

Bạn cũng có thể xâu chuỗi kết quả của mình bằng câu lệnh WITH. Ví dụ:

WITH tab1 as (Your SQL statement),
tab2 as ( SELECT ... FROM tab1 WHERE your filter),
tab3 as ( SELECT ... FROM tab2 WHERE your filter)
SELECT * FROM tab3;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.