我正在使用PostgreSQL 9,我希望在表RP中为RQ中的所有元组查找最近的邻居,比较日期(t),但是我得到了以下错误:
错误: FROM中的子查询不能引用相同查询级别的其他关系。
使用此查询:
SELECT *
FROM RQ, (SELECT * FROM RP ORDER BY ABS(RP.t - RQ.t) LIMIT 1) AS RA子查询中的RQ.t似乎是问题所在。如何避免此错误?如何从子查询访问RQ
发布于 2012-05-27 14:11:04
更新:
LATERAL联接允许这样做,并且是在Postgres9.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;关联子查询因性能差的而臭名昭著。这种查询--显然是计算您想要的--特别糟糕,因为表达式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;同样,如果您想要整行:
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;注意括号与复合类型的使用!没有帕伦是多余的。在手册这里和这里中有更多关于这一点的信息。
用PostgreSQL 9.1进行测试。在广场小提琴上的演示。
发布于 2012-05-28 01:22:21
相关的子查询,没有索引,无论如何都要进行交叉连接。因此,表达查询的另一种方式是:
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这种方法的优点是没有交叉连接,也没有相关的子查询。
https://stackoverflow.com/questions/10773568
复制相似问题