5

使用 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.
4

2 回答 2

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;
于 2013-05-09T05:39:07.250 回答
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有关此相关答案中的技术的更多信息:

我想如果你有GiST 索引g.geom计划者可能足够聪明,可以从中选择关闭项目。不确定,没测试。否则,这种情况CROSS JOIN会导致 O(N²) 并且在更大的表中性能可能会很快失控。

我在这里引用 Postgis 手册:

仅当其中一个几何图形是常量时(不在子查询/cte 中),索引才会生效。例如'SRID=3005;POINT(1011102 450541)'::geometry,而不是a.geom

所以你在这里可能不走运。

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

于 2013-05-09T22:40:28.010 回答