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

これにより、ユーザーごとに 1 つの行が表示され、最も近い犬が表示されます。

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 のマニュアルを引用します。

インデックスは、ジオメトリの 1 つが定数である (サブクエリ/cte ではない) 場合にのみ有効になります。たとえば'SRID=3005;POINT(1011102 450541)'::geometry、代わりにa.geom

だから、あなたはここで運が悪いかもしれません。

マニュアルによると、ST_Distance()正確な並べ替え順序を取得するために並べ替える必要がある場合がありますが、最も遠いものを取得するべきではありません。それは意味がありません。

于 2013-05-09T22:40:28.010 に答える
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 を想定) は空ではありません。usersとの間に相関関係があるべきかどうかはわかりませんdogs


ユーザーに最も近い犬を見つけるには、このクエリを使用できます。スカラー サブクエリは犬の 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 に答える