I'm working with PostgreSQL 9 and I want to find the nearest neighbor inside table RP
for all tuples in RQ
, comparing the dates (t
), but I get this error:
ERROR: subquery in FROM cannot refer to other relations of same query level
using this query:
SELECT *
FROM RQ, (SELECT * FROM RP ORDER BY ABS(RP.t - RQ.t) LIMIT 1) AS RA
RQ.t
in subquery seems to be the problem. How can I avoid this error? How can I get access from subquery to RQ
?
Update:
LATERAL
joins allow that and were introduced with Postgres 9.3. Details:The reason is in the error message. One element of the
FROM
list cannot refer to another element of theFROM
list on the same level. It is not visible for a peer on the same level. You could solve this with a correlated subquery:Obviously, you don't care which row from
RP
you pick from a set of equally close rows, so I do the same.However, a subquery expression in the
SELECT
list can only return one column. If you want more than one or all columns from the tableRP
, use something like this subquery construct:I assume the existence of a primary key
id
in both tables.Correlated subqueries are infamous for bad performance. This kind of query - while obviously computing what you want - will suck in particular, because the expression
rp.t - rq.t
cannot use an index. Performance will deteriorate drastically with bigger tables.This rewritten query should be able to utilize an index on
RP.t
, which should perform much faster with big tables.Again, if you want the whole row:
Note the use of parentheses with composite types! No paren is redundant here. More about that in the manual here and here.
Tested with PostgreSQL 9.1. Demo on sqlfiddle.
The correlated subqueries, without an index, are going to do a cross join anyway. So, another way of expressing the query is:
There is another method, which is a bit more complicated. This requires using the cumulative sum.
Here is the idea. Combine all the rp and rq values together. Now, enumerate them by the closest rp value. That is, create a flag for rp and take the cumulative sum. As a result, all the rq values between two rp values have the same rp index.
The closest value to a given rq value has an rp index the same as the rq value or one more. Calculating the the rq_index uses the cumulative sum.
The following query puts this together:
The advantage of this approach is that there is no cross join and no correlated subqueries.