2013-05-09 33 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

相關問題