错误:FROM中的子查询不能引用相同查询级别的其他关系

Pan*_*red 4 sql postgresql subquery nearest-neighbor correlated-subquery

我正在使用PostgreSQL 9,我想在RP所有元组中查找表中最近的邻居RQ,比较日期(t),但是我得到了这个错误:

错误:FROM中的子查询不能引用相同查询级别的其他关系

使用此查询:

SELECT *
FROM RQ, (SELECT * FROM RP ORDER BY ABS(RP.t - RQ.t) LIMIT 1) AS RA
Run Code Online (Sandbox Code Playgroud)

RQ.t在子查询中似乎是问题所在.我怎样才能避免这个错误?如何从子查询访问RQ

Erw*_*ter 5

更新:

LATERAL加入允许,并与Postgres 9.3一起介绍.细节:


原因在于错误消息.FROM列表的一个元素不能FROM在同一级别引用列表的另一个元素.对于同一级别的对等体,它是不可见的.您可以使用相关子查询来解决此问题:

SELECT *, (SELECT t FROM rp ORDER BY abs(rp.t - rq.t) LIMIT 1) AS ra
FROM   rq
Run Code Online (Sandbox Code Playgroud)

显然,你不关心从哪一行中RP选择一行等距离的行,所以我也这样做.

但是,SELECT列表中的子查询表达式只能返回列.如果您需要表中的多个或多个列RP,请使用类似此子查询构造的内容:
我假设id两个表中都存在主键.

SELECT id, t, (ra).*
FROM (
    SELECT *, (SELECT rp FROM rp ORDER BY abs(rp.t - rq.t) LIMIT 1) AS ra
    FROM   rq
    ) x;
Run Code Online (Sandbox Code Playgroud)

相关的子查询因性能不佳而臭名昭着.这种查询 - 虽然显然计算你想要的东西 - 会特别糟糕,因为表达式rp.t - rq.t不能使用索引.较大的桌子会使性能急剧恶化.


这样重写后的查询应该能够利用一个在指数RP.t,其应执行多少与大表更快.

WITH x AS (
    SELECT * 
         ,(SELECT t
           FROM   rp
           WHERE  rp.t <  rq.t
           ORDER  BY rp.t DESC
           LIMIT  1) AS t_pre

         ,(SELECT t
           FROM   rp
           WHERE  rp.t >= rq.t
           ORDER  BY rp.t
           LIMIT  1) AS t_post
    FROM   rq
    )
SELECT id, t
      ,CASE WHEN (t_post - t) < (t - t_pre)
            THEN t_post
            ELSE COALESCE(t_pre, t_post) END AS ra
FROM   x;
Run Code Online (Sandbox Code Playgroud)

再次,如果你想要整行:

WITH x AS (
    SELECT * 
         ,(SELECT rp
           FROM   rp
           WHERE  rp.t <  rq.t
           ORDER  BY rp.t DESC
           LIMIT  1) AS t_pre

         ,(SELECT rp
           FROM   rp
           WHERE  rp.t >= rq.t
           ORDER  BY rp.t
           LIMIT  1) AS t_post
    FROM   rq
    ), y AS (
    SELECT id, t
          ,CASE WHEN ((t_post).t - t) < (t - (t_pre).t)
                THEN t_post
                ELSE COALESCE(t_pre, t_post) END AS ra
    FROM   x
    )
SELECT id AS rq_id, t AS rq_t, (ra).*
FROM   y 
ORDER  BY 2;
Run Code Online (Sandbox Code Playgroud)

注意括号与复合类型的使用!没有paren在这里是多余的.在这里这里的手册中有更多相关信息.

使用PostgreSQL 9.1进行测试.在sqlfiddle上演示.