2013-05-09 720 views
3

使用PostgreSQL-9.1和PostGIS 2.0.1时,在执行包含返回多列的子查询的SELECT查询时,出现错误subquery must return only one columnPostgreSQL错误:子查询必须只返回一列

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

查询

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
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; 
+0

我试图扩大查询(更新问题),现在theres错误'错误:表的无效引用FROM-clause条目“l”' '提示:有一个表“l”的条目,但它不能从这部分查询中引用。' – Nyxynyx 2013-05-09 06:39:07

+0

对于第二个查询,需要200ms才能返回500行。然而,就像Erwin的回答一样,这个查询返回了离每个'l.geom'最远的'g.geom'。那么也许我正在使用错误的CRS? 'geom' cols目前是'POINT,2163' – Nyxynyx 2013-05-10 06:04:28

+0

在这里抓住吸管,尝试在子查询中使用'ORDER BY ST_Distance(l.geom,g.geom)'? – RichardTheKiwi 2013-05-10 08:42:11

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 indexg.geom,规划可能是足够聪明,只是从中挑选关闭项目。不确定,没有测试。否则,这种CROSS JOIN会导致O(N²),并且性能可能会随着更大的表格快速失控。

我引用POSTGIS手动here

Index only kicks in if one of the geometries is a constant (not in a subquery/cte). e.g. 'SRID=3005;POINT(1011102 450541)'::geometry instead of a.geom

所以,你可能是出于运气在这里。

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

+0

我可能是错的,但是这个查询返回的'g.geom'离对应的最远'l.geom'。查询大约需要8秒钟才能返回500行。看起来似乎没有使用GiST指数。 – Nyxynyx 2013-05-10 06:02:21

+0

我在答复中加了一点。 – 2013-05-10 07:00:02

相关问题