Як використовувати декілька операторів WITH в одному запиті PostgreSQL?


96

Я хотів би "оголосити", що є фактично декількома таблицями TEMP, використовуючи оператор WITH. Запит, який я намагаюся виконати, відповідає:

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

Я прочитав документацію PostgreSQL і дослідив використання декількох WITHтверджень, і не зміг знайти відповіді.


Спробуйте кому перед другим withтвердженням, будь-яким іншим після. Не впевнений щодо postgres, але це звичайний синтаксис із сервером Oracle та sql
msheikh25,

Я спробував використовувати кому, а пізніше крапку з комою, і все ще були синтаксичні помилки: ERROR: syntax error at or near "WITH"для коми та ERROR: syntax error at or near ";"крапки з комою.
Грег

Відповіді:


155

За іншими коментарями перед другим загальним виразом таблиці [CTE] передує кома, а не оператор WITH, тому

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

З точки зору вашого фактичного запиту, цей синтаксис повинен працювати в PostgreSql, Oracle та sql-сервері, а згодом, як правило, ви продовжите WITHз крапкою з комою ( ;WTIH), але це тому, що зазвичай люди sql-сервера (включаючи мене) не закінчуються попередні оператори, які потрібно закінчити до визначення КТЕ ...

Однак зауважте, що у вас була друга проблема із синтаксисом стосовно вашого WHEREвисловлювання. WHERE date IN table_2недійсний, оскільки ви ніколи фактично не посилаєтесь на значення / стовпець з таблиці_2. Я віддаю перевагу INNER JOINбільш INабо Existsтак ось синтаксис , який повинен працювати з 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
;

Якщо ви хочете зберегти те, що було у вас, яке зазвичай ІСНУЄ, було б краще, ніж IN, але для використання IN вам потрібен фактичний оператор SELECT у вашому де.

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

IN дуже проблематично, коли dateце потенційно може бути, NULLякщо ви не хочете використовувати a, JOINтоді я б запропонував EXISTS. AS наступним чином:

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

2
Дякую за глибоке пояснення, синтаксис спрацював :)
Грег

рада допомогти. Я не можу знайти статтю про невикористання IN, але настійно рекомендую використовувати JOIN або ІСНУЄ над IN. Якщо у вашому наборі результатів є нуль, що трапиться, ви отримаєте кожен запис, а не лише той, який ви хочете. Це дивно, але саме так працює більшість RDBM. спробуйте перевірити пошук на ньому, я знаю хорошу відповідь, яку я бачив про те, що теж було на цьому сайті ... у будь-якому випадку, спокійної ночі
Метт

5

Ви також можете зв'язати свої результати за допомогою оператора WITH. Наприклад:

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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.