如何调试PostgreSQL中的公共表表达式?

如何调试PostgreSQL中的公共表表达式?,sql,postgresql,common-table-expression,Sql,Postgresql,Common Table Expression,我在一个查询中遇到了一个问题,其中一个CTE没有返回任何行。但这很难被注意到,而且调试lastet也花了很长时间 是否可以在Postgres中输出所有CTE而不注释主查询 在本例中,CTE质心以增量的方式添加到之前运行良好的函数中。如果网格为空,它应该返回行。我修复的错误是它没有,因为它是从空的CTE网格中选择的。现在,当我描述这个问题时,很明显它失败的原因,但是当您编写它并调试时,可能会发生各种情况,例如混合几何体SRID、错误的SRID等。解释分析外观以单独报告CTE 当我运行Postgre

我在一个查询中遇到了一个问题,其中一个CTE没有返回任何行。但这很难被注意到,而且调试lastet也花了很长时间

是否可以在Postgres中输出所有CTE而不注释主查询


在本例中,CTE质心以增量的方式添加到之前运行良好的函数中。如果网格为空,它应该返回行。我修复的错误是它没有,因为它是从空的CTE网格中选择的。现在,当我描述这个问题时,很明显它失败的原因,但是当您编写它并调试时,可能会发生各种情况,例如混合几何体SRID、错误的SRID等。

解释分析外观以单独报告CTE

当我运行Postgresql 9.4时,它单独显示了CTE,在结果部分,它确实显示从x上的CTE扫描返回的实际行数为0

explain analyze
with x as (select 1 where false),
     y as (select 2 where true)
select * from x, y;
返回:

Nested Loop  (cost=0.02..0.07 rows=1 width=8) (actual time=0.002..0.002 rows=0 loops=1)
  Output: x."?column?", y."?column?"
  CTE x
    ->  Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.000..0.000 rows=0 loops=1)
          Output: 1
          One-Time Filter: false
  CTE y
    ->  Result  (cost=0.00..0.01 rows=1 width=0) (never executed)
          Output: 2
  ->  CTE Scan on x  (cost=0.00..0.02 rows=1 width=4) (actual time=0.002..0.002 rows=0 loops=1)
        Output: x."?column?"
  ->  CTE Scan on y  (cost=0.00..0.02 rows=1 width=4) (never executed)
        Output: y."?column?"
Planning time: 0.034 ms
Execution time: 0.018 ms
我不知道解释会总是这样显示数据,我怀疑这取决于Postgresql如何决定优化查询,但这应该是一个很好的起点

解释位于

的文档交叉联接的问题是,当其中一个派生表为空时,它将不会产生任何输出:

with x as (select 1 where false),
     y as (select 2 where true)
select * from x, y;
你需要像外部交叉连接这样的东西

在SQL Server中,有很多外部应用程序:

您可以使用LEFT JOIN-LATERAL模拟此行为,但它看起来有点难看:

;WITH x(c) AS (SELECT 1 WHERE false),
      y(d) AS (SELECT 2 WHERE true)
SELECT * 
FROM (VALUES ('Base row')) AS s(val)
LEFT JOIN LATERAL (SELECT * FROM x) AS x(c) ON true
LEFT JOIN LATERAL (SELECT * FROM y) AS y(d) ON true;
输出:

╔═══════════╦═════════╦═══╗
║   val     ║   c     ║ d ║
╠═══════════╬═════════╬═══╣
║ Base row  ║ (null)  ║ 2 ║
╚═══════════╩═════════╩═══╝
或在此情况下使用简单的左连接:

;WITH x(c) AS (SELECT 1 WHERE false),
     y(d) AS (SELECT 2 WHERE true)
SELECT * 
FROM (VALUES ('Base row')) AS s(val)
LEFT JOIN x ON true
LEFT JOIN y ON true;

如果你不知道它是做什么的,你为什么要写这样的东西呢?@joop当你不小心犯了一个错误,你总是知道你的程序是做什么的。这是一个小细节,你错过了,使事情不工作。我添加了与我一起工作的真实查询。。。。从网格中选择count*=0是一种糟糕的样式,可以避免,IMHO。[我甚至不知道它的语法是否有效;我会在这里使用NOT EXISTS构造IIUC片段]@joop很好的观点,忘记了那句话我刚刚做了一个示例查询,当然我知道它有0行。但是这个工具非常有趣,谢谢!提示:选择*从x完全连接y为真
╔═══════════╦═════════╦═══╗
║   val     ║   c     ║ d ║
╠═══════════╬═════════╬═══╣
║ Base row  ║ (null)  ║ 2 ║
╚═══════════╩═════════╩═══╝
;WITH x(c) AS (SELECT 1 WHERE false),
     y(d) AS (SELECT 2 WHERE true)
SELECT * 
FROM (VALUES ('Base row')) AS s(val)
LEFT JOIN x ON true
LEFT JOIN y ON true;