【问题标题】:ERROR: subquery in FROM cannot refer to other relations of same query level错误:FROM 中的子查询不能引用相同查询级别的其他关系
【发布时间】:2012-06-02 04:00:05
【问题描述】:

我正在使用 PostgreSQL 9,我想为 RQ 中的所有元组在表 RP 内找到最近的邻居,比较日期 (t),但我收到此错误:

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

使用这个查询:

SELECT *
FROM RQ, (SELECT * FROM RP ORDER BY ABS(RP.t - RQ.t) LIMIT 1) AS RA

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

【问题讨论】:

标签: sql postgresql subquery nearest-neighbor correlated-subquery


【解决方案1】:

更新:

LATERAL 连接允许这样做,并且是在 Postgres 9.3 中引入的。详情:


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

SELECT *, (SELECT t FROM rp ORDER BY abs(rp.t - rq.t) LIMIT 1) AS ra
FROM   rq

显然,您并不关心您从一组同样接近的行中选择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;

相关子查询因性能不佳而臭名昭著。这种查询——虽然显然是在计算你想要的——尤其会suck,因为表达式rp.t - rq.t 不能使用索引。表越大,性能会急剧下降。


这个重写的查询应该能够利用 RP.t 上的索引,这应该在大表中更快。。 p>

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;

同样,如果你想要整行:

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;

注意复合类型的括号的使用!这里没有多余的括号。有关更多信息,请参阅手册 herehere

使用 PostgreSQL 9.1 测试。 Demo on sqlfiddle.

【讨论】:

    【解决方案2】:

    没有索引的相关子查询无论如何都会进行交叉连接。所以,另一种表达查询的方式是:

    select rp.*, min(abs(rp.t - rq.t))
    from rp cross join
         rq
    group by <rp.*> -- <== need to replace with all columns
    

    还有另一种方法,它有点复杂。这需要使用累积和。

    这就是想法。将所有 rp 和 rq 值组合在一起。现在,用最接近的 rp 值枚举它们。也就是说,为 rp 创建一个标志并获取累积和。因此,两个 rp 值之间的所有 rq 值都具有相同的 rp 索引。

    与给定 rq 值最接近的值具有与 rq 值相同或更多的 rp 索引。计算 rq_index 使用累积和。

    以下查询将这些放在一起:

    with rqi as (select t.*, sum(isRQ) over (order by t) as rq_index
                 from (select rq.t, 0 as isRP, <NULL for each rp column>
                       from rq
                       union all
                       select rq.t, 1 as isRP, rp.* 
                       from rp
                      ) t
                ) t
    select rp.*,
           (case when abs(rqprev.t - rp.t) < abs(rqnext.t - rp.t)
                 then abs(rqprev.t - rp.t)
                 else abs(rqnext.t - rp.t)
            end) as closest_value
    from (select *
          from t
          where isRP = 0
         ) rp join
         (select *
          from t
          where isRP = 1
         ) rqprev
         on rp.rp_index = rqprev.rp_index join
         (select *
          from t
          where isRP = 1
         ) rqnext
         on rp.rp_index+1 = rpnext.rq_index
    

    这种方法的优点是没有交叉连接,也没有相关的子查询。

    【讨论】:

    • 我知道这是一篇旧帖子,但如果有人在使用 RedShift 时遇到此错误,则可能是由于缺少列错误。我正在做一个简单的“SELECT a, b, c FROM (SELECT a, b FROM a1) t1, (SELECT col1 a, c FROM a2) t2 WHERE t1.a = t2.a”,其中 col1 列不在表 a2 中.希望这对某人有所帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-15
    • 1970-01-01
    • 2013-06-20
    • 2019-01-09
    • 2017-12-30
    相关资源
    最近更新 更多