PostgreSQL错误:子查询必须只返回一列

时间:2013-05-09 05:32:52

标签: sql postgresql greatest-n-per-group postgis postgresql-9.2

使用PostgreSQL-9.1和PostGIS 2.0.1,在进行包含返回多列的子查询的SELECT查询时,我收到错误subquery must return only one column

如何修改查询/子查询以返回多个列?

查询

SELECT l.id, l.lat, l.lng, l.geom,
        (SELECT g.id, g.lat, g.lng, ST_Distance(l.geom, g.geom)
        FROM stage.dogs as g
        LIMIT 1)

FROM stage.users As l

完整查询

SELECT l.id, l.lat, l.lng, l.geom,
    g.id, g.lat, g.lng, ST_Distance(l.geom, g.geom) 
FROM stage.users As l
CROSS JOIN (SELECT *
    FROM stage.dogs as g
    ORDER BY g.geom <-> l.geom 
    LIMIT 1) as g

错误

ERROR: invalid reference to FROM-clause entry for table "l"
SQL state: 42P01
Hint: There is an entry for table "l", but it cannot be referenced from this part of the query.

2 个答案:

答案 0 :(得分:2)

SELECT l.id, l.lat, l.lng, l.geom,
       g.id, g.lat, g.lng, ST_Distance(l.geom, g.geom)
FROM stage.users As l
CROSS JOIN (SELECT * FROM stage.dogs LIMIT 1) as g

这就是你所拥有的(假设stage.dogs)不是空的。不确定usersdogs之间是否应该存在关联。


要查找与用户最近的狗,您可以使用此查询。标量子查询找到狗的ID,并连接回表以检索其他列。

SELECT l.id, l.lat, l.lng, l.geom,
       g.id, g.lat, g.lng, ST_Distance(l.geom, g.geom)
FROM (
    SELECT l1.*, (SELECT g1.id
                  FROM stage.dogs as g
                  ORDER BY g.geom <-> l.geom 
                  LIMIT 1) g_id
    FROM stage.users As l1
) l
JOIN stage.dogs as g ON g.id = l.g_id;

公平警告,这不是一个快速查询。


冒着执行速度更慢的风险,请参阅下面的查询以查看多个表

SELECT l.id, l.lat, l.lng, l.geom,
       g.id, g.lat, g.lng, ST_Distance(l.geom, g.geom) dog_distance,
       c.id, c.lat, c.lng, ST_Distance(l.geom, c.geom) cat_distance,
       b.id, b.lat, b.lng, ST_Distance(l.geom, b.geom) bird_distance
FROM (
    SELECT l1.*, (SELECT g1.id
                  FROM stage.dogs as g1
                  ORDER BY g1.geom <-> l.geom 
                  LIMIT 1) dog_id,
                 (SELECT c1.id
                  FROM stage.cats as c1
                  ORDER BY c1.geom <-> l.geom 
                  LIMIT 1) cat_id,
                 (SELECT b1.id
                  FROM stage.cats as b1
                  ORDER BY b1.geom <-> l.geom 
                  LIMIT 1) bird_id
    FROM stage.users As l1
) l
LEFT JOIN stage.dogs as g ON g.id = l.dog_id
LEFT JOIN stage.dogs as c ON c.id = l.cat_id
LEFT JOIN stage.dogs as b ON b.id = l.bird_id;

答案 1 :(得分:2)

这为每位用户提供了一行最近的狗:

SELECT DISTINCT ON (l.id)
       l.id, l.lat, l.lng, l.geom
      ,g.id, g.lat, g.lng, ST_Distance(l.geom, g.geom) 
FROM   stage.users     l
CROSS  JOIN stage.dogs g
ORDER  BY l.id, (l.geom <-> g.geom)

在此相关答案中有关DISTINCT ON技术的更多信息:

我想如果g.geom上有GiST index,那么规划师可能会非常聪明,只能从中选择关闭项目。不确定,没试过。否则,这种CROSS JOIN将导致O(N²),并且使用更大的表格可能会使性能失控。

我引用了Postgis手册here

  

如果其中一个几何是一个常量(不在a中),则只能启动索引   子查询/ CTE)。例如'SRID=3005;POINT(1011102 450541)'::geometry代替a.geom

所以你可能在这里运气不好。

根据手册,您可能需要ST_Distance()订购以获得精确的排序顺序,但您不应该获得最远的顺序。这毫无意义。