2015-08-06 6 views
1

Учитывая простой PL/PgSQL функция:PL/PGSQL всегда возвращает массив или список массивов

CREATE OR REPLACE FUNCTION foo (point geometry 
           , OUT _street text 
           , OUT _gid int 
           , OUT distance real) 
AS $$ 
BEGIN 

    SELECT min(distance(point,geom)) as dist, gid, name into distance, _gid, _street 
    from streets 
    where geometria && Expand(point,0.001) group by gid, name order by dist limit 1; 

END; 
$$ LANGUAGE plpgsql; 

результаты в чем-то сродни:

geobase=# select foo(GeomFromText('POINT(-99.124191496999 19.3490666368031)',4326)); 
         foo      
------------------------------------------------- 
("PASEO DE LOS FRAMBOYANES",345483,0.000118338) 

Что хорошо, за исключением того, что кроме Я бы ожидать чего-то более похожее на это:

  _street   | _gid | distance  
--------------------------+--------+------------- 
PASEO DE LOS FRAMBOYANES | 345483 | 0.000118338 

Я пробовал варианты с пунктом RETURN, определяя его как строку rowtype, record и even table, но я всегда получаю кортеж или массив, как указано в примере. Любые подсказки относительно того, как получить результат способом, подобным таблице?

ответ

1

попробовать select * from foo(GeomFromText('POINT(-99.124191496999 19.3490666368031)',4326));? ..

+0

Это работает как задумано! Большое вам спасибо за ваш быстрый ответ. –

+0

@AaronRivacoba Если это правильный ответ, вы должны его принять. – Bill

0

Вопрос спросил был дан ответ много раз. Для разложения возвращаемый тип строки использовать

SELECT * FROM foo(...); 

Как здесь:


Но есть больше.

Ваша функция с менее запутанным синтаксисом, меньше ошибок и упрощены:

CREATE OR REPLACE FUNCTION foo (_point geometry) 
    RETURNS TABLE (street text, gid int, distance real) AS 
$func$ 
BEGIN 

RETRUN QUERY 
SELECT s.name, s.gid, distance(_point, s.geom) 
FROM streets s 
WHERE s.geometria && expand(_point, 0.001) 
ORDER BY 3 
LIMIT 1; 

END 
$func$ LANGUAGE plpgsql; 

Поскольку у вас есть ORDER BY ... LIMIT 1, вам не нужно min() и GROUP BY вообще.

Обратите внимание, как я столчил все столбцы, чтобы избежать конфликтов имен.

Существует одна тонкая разница: Если запрос находит нет строки ваших оригинальных возвращает строку со значениями NULL вместо, в то время как моя функция фактически не возвращает строки. Как правило, вам понадобится последний.

То же, эквивалентной простой функции SQL:

CREATE OR REPLACE FUNCTION foo (_point geometry) 
    RETURNS TABLE (street text, gid int, distance real) AS 
$func$ 
SELECT s.name, s.gid, distance(_point, s.geom) 
FROM streets s 
WHERE s.geometria && expand(_point, 0.001) 
ORDER BY 3 
LIMIT 1 
$func$ LANGUAGE sql; 

Но это не очень эффективно с большими таблицами. Вы будете заинтересованы в KNN (к-ближайших соседей) поиск в PostGIS:

+0

Большое спасибо за ваш ответ. У меня есть почти иррациональное отталкивание от использования числовых параметров, как в вашем примере: SELECT s.name ...ORDER BY 3 Есть ли какое-то преимущество в этом, а не более болтливое «ORDER BY distance»? –

+0

@AaronRivacoba: Отсутствие производительности. Просто синтаксический ярлык, который особенно удобен для длинных выражений в списке SELECT. Тем более, что в примере, когда я не назначаю псевдоним столбца, который не имеет другого смысла (не отображается вне функции). В столбце alias distance возникает вопрос о возможных конфликтах именования с параметром OUT функции (без конфликта в * этом случае). Вам нужно будет использовать 'distance (_point, s.geom)' ** 'AS distance' **' ... ORDER BY distance'. Опираясь на автоматический псевдоним кажется еще менее чистым. –