如何在一个PostgreSQL查询中使用多个WITH语句?


105

我想使用WITH语句“声明”什么是有效的多个TEMP表。我尝试执行的查询大致如下:

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 server的常规语法
msheikh25 '16

我尝试使用逗号,后来又使用了分号,但仍然存在语法错误:ERROR: syntax error at or near "WITH"逗号和ERROR: syntax error at or near ";"分号。
格雷格

Answers:


167

根据其他注释,第二个公共表表达式[CTE]前面带有逗号而不是WITH语句,因此

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

就您的实际查询而言,此语法应在PostgreSql,Oracle和sql-server中起作用,那么以后通常您将WITH使用分号(;WTIH)进行操作,但这是因为通常sql-server人员(包括我自己)不会结束在定义CTE之前需要结束的先前语句...

但是请注意,关于WHERE语句,您还有第二个语法问题。 WHERE date IN table_2无效,因为您从未实际引用过table_2中的值/列。我喜欢INNER JOININ或者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
;

如果要保持原样,通常EXISTS比IN更好,但是要使用IN,则需要在实际位置使用SELECT语句。

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

如果date很可能出现INNULLJOIN话,我会提出很大的问题EXISTS。如下:

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

乐意效劳。我找不到有关不使用IN的文章,但强烈建议使用IN上的JOIN或EXISTS。如果结果集中存在空值,那将是每条记录,而不仅仅是您想要的记录。这很奇怪,但这是大多数RDBM运作的方式。尝试检查一下搜索结果,我知道我在该网站上也看到过很好的答案...总之,晚上好
Matt

8

您也可以使用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;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.