2016-07-01 111 views
22

Vorrei "dichiarare" quali sono effettivamente più tabelle TEMP utilizzando l'istruzione WITH. La query che sto cercando di eseguire è lungo le linee di:Come utilizzare più istruzioni WITH in una query PostgreSQL?

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 

che ho letto e studiato PostgreSQL documentation ad utilizzare molteplici WITH dichiarazioni e non è riuscito a trovare una risposta.

+0

Provare una virgola prima della seconda istruzione 'with' qualsiasi altra dopo. Non sono sicuro di postgres ma questa è la normale sintassi con Oracle e sql server – mo2

+0

Ho provato ad usare una virgola e più tardi un punto e virgola e c'erano ancora errori di sintassi: 'ERRORE: errore di sintassi in corrispondenza di" WITH "vicino alla virgola e' ERRORE: errore di sintassi in corrispondenza o vicino a ";" 'per il punto e virgola. – Greg

risposta

39

Per gli altri commenti la seconda Common Table Expression [CTE] è preceduto da una virgola, non un'istruzione WITH così

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

In termini di query effettiva questa sintassi dovrebbe funzionare in PostgreSQL, Oracle e SQL -server, beh il più tardi in genere si procede con WITH con un punto e virgola (;WTIH), ma ciò è dovuto al fatto che in genere sql-server (incluso) non termina le istruzioni precedenti che devono essere terminate prima che venga definito un CTE.

Si noti tuttavia che si è verificato un secondo problema di sintassi in relazione a la nostra dichiarazione WHERE. WHERE date IN table_2 non è valido perché in realtà non si fa mai riferimento a un valore/colonna da table_2. Io preferisco INNER JOIN oltre IN o Exists ecco una sintassi che dovrebbe funzionare con un 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 
; 

Se si desidera mantenere il modo in cui avete avuto che in genere ESISTE sarebbe meglio che in ma da utilizzare per in voi hai bisogno di una vera e propria istruzione SELECT nel tuo dove.

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

in è molto problematico quando date potrebbe potenzialmente essere NULL quindi se non si vuole usare un JOIN allora suggerirei EXISTS. AS segue:

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

Grazie per la spiegazione approfondita, la sintassi ha funzionato :) – Greg

+0

felice di aiutare. Non riesco a trovare l'articolo su non usare IN, ma suggerisco caldamente di usare un JOIN o EXISTS su IN. Se esiste un valore nullo nel set di risultati, ciò che accade è che otterrai ogni record non solo quelli che desideri. È strano ma è il modo in cui funziona la maggior parte degli RDBM. prova a controllare una ricerca su di esso, so che la buona risposta che ho visto su questo era anche su questo sito ... comunque, buona notte – Matt

+0

mi hai salvato un sacco di tempo amico, grazie !!! – Juan