2016-03-02 2 views
0

Я пытаюсь написать функцию plpgsql, которая проходит через таблицу. В каждом цикле он вытягивает строку из таблицы, сохраняет ее в записи, а затем использует эту запись в предложении соединения запроса. Вот мой код:Использование строки в виде таблицы в запросе внутри функции PLpgSQL

CREATE OR REPLACE FUNCTION "testfncjh2"() RETURNS int 
    IMMUTABLE 
    SECURITY DEFINER 
AS $dbvis$ 
DECLARE 
     counter int; 
     tablesize int; 
     rec1 record; 
     tablename text; 
     rec2 record; 
BEGIN 
counter = 0; 
for rec1 in SELECT * FROM poilocations_sridconv loop 

raise notice 'here'; 
execute $$ select count(*) from $$||rec1||$$ $$ into tablesize; 

     while counter < tablesize loop 

       counter = counter + 1; 
       raise notice 'hi'; 
       execute $$ select count(*) from cities_sridconv $$ into tablesize; 
       end loop; 
    end loop; 
return counter; 
END; 
$dbvis$ LANGUAGE plpgsql; 

Каждый раз, когда я запускаю это, я получаю следующее сообщение об ошибке:

ERROR: could not find array type for data type record

Есть ли способ использовать строку в виде таблицы в запросе внутри вложенных циклов?

Моя конечная цель - построить функцию, которая проходит через таблицу, вытягивая строку из этой таблицы в каждом цикле. В каждом цикле вычисляется номер COUNTER с использованием строки, затем выполняется запрос в зависимости от строки и COUNTER. Зная, что этот код в настоящее время очень испорчено, я отправляю его ниже, чтобы дать представление о том, что я пытаюсь сделать:

CREATE OR REPLACE FUNCTION «testfncjh»() возвращает пустого непреложного DEFINER БЕЗОПАСНОСТИ AS $ dbvis $ DECLARE counter int; tablesize int; rec1 запись; tablename текст; rec2 запись; НАЧАТЬ

for rec1 in SELECT * FROM poilocations_sridconv loop 
     counter = 0; 
     execute $$ select count(*) 
       from $$||rec1||$$ a 
       join 
         cities_srid_conv b 
       on  right(a.geom_wgs_pois,$$||counter||$$) = right(b.geom_wgs_pois,$$||counter||$$) $$ into tablesize; 

     raise notice 'got through first execute'; 
     while tablesize = 0 loop 

       counter = counter + 1; 
       execute $$ select count(*) 
       from '||rec1||' a 
       join 
         cities_srid_conv b 
       on  right(a.geom_wgs_pois,'||counter||') = right(b.geom_wgs_pois,'||counter||') $$ into tablesize; 
       raise notice 'hi'; 
       end loop; 

     EXECUTE 
       'select 
         poiname, 
         name as cityname, 
         postgis.ST_Distance(postgis.ST_GeomFromText(''POINT(poilat poilong)''), 
              postgis.ST_GeomFromText(''POINT(citylat citylong)'') 
              ) as distance 
       from (select a.poiname, 
           a.latitude::text as poilat, 
           a.longitude::text as poilong, 
           b.geonameid, 
           b.name, 
           b.latitude as citylat, 
           b.longitude as citylong 
         from '||rec1||' a 
         join cities_srid_conv b 
         on right(a.geom_wgs_pois,'||counter||') = right(b.geom_wgs_pois,'||counter||')) 
         ) x 
       order by distance 
     limit 1' 

     poi_cities_match (poiname, cityname, distance); ------SQL STATEMENT TO INSERT CLOSEST CITY TO TABLE POI_CITIES_MATCH 
    end loop; 

END; 
$dbvis$ LANGUAGE plpgsql; 

Я бегу на базе данных PostgreSQL 8.2.15.

Также, извините за повторную отправку. Мне пришлось удалить некоторые данные из оригинала.

ответ

0

Я думаю, вы должны иметь возможность использовать композитные типы для того, что вы хотите. Я упростил ваш верхний пример и использовал составные типы следующим образом.

CREATE OR REPLACE FUNCTION "testfncjh2"() RETURNS int 
    IMMUTABLE 
    SECURITY DEFINER 
AS $dbvis$ 
DECLARE 
     counter int; 
     tablesize int; 
     rec1 poilocations_sridconv; 
     tablename text; 
     rec2 record; 
BEGIN 
counter = 0; 
for rec1 in SELECT * FROM poilocations_sridconv loop 
    raise notice 'here'; 
    select count(*) FROM (select (rec1).*)theRecord into counter; 
end loop; 
return counter; 
END; 
$dbvis$ LANGUAGE plpgsql; 

Основные изменения будучи rec1 poilocations_sridconv; линии и используя (select (rec1).*)

Надеются, что это помогает.

EDIT: Я должен отметить, что функция не делает то же самое, что и в вопросе выше. Это как пример того, как вы могли бы использовать запись в виде таблицы в запросе.

0

У вас есть несколько проблем с кодом (кроме, может быть, от вашей логики).

Прежде всего, вы не должны использовать record в качестве источника таблицы в JOIN. Вместо этого отфильтруйте вторую таблицу для строк, которые соответствуют некоторому полю, из record.

Во-вторых, вы должны использовать функцию format() вместо сборки строк с помощью оператора ||. Но вы не можете, потому что используете доисторическую версию 8.2. Это из эпохи пещерной живописи (да, это так плохо). ОБНОВИТЬ!

В-третьих, не слишком усложняйте свои запросы. Суб-запрос здесь не нужен.

Помещенный вместе, второй динамический запрос от вашего реального кода позволит сократить это:

EXECUTE format(
    'SELECT b.name, 
      postgis.ST_Distance(postgis.ST_SetSRID(postgis.ST_MakePoint(%1$I.longitude, %1$I.latitude), 4326), 
           postgis.ST_SetSRID(postgis.ST_MakePoint(b.longitude, b.latitude), 4326)) 
    FROM cities_srid_conv b 
    WHERE right(%1$I.geom_wgs_pois, %2$L) = right(b.geom_wgs_pois, %2$L) 
    ORDER BY distance 
    LIMIT 1', rec1, counter) INTO cityname, distance; 

poi_cities_match (rec1.poiname, cityname, distance); ------SQL STATEMENT TO INSERT CLOSEST CITY TO TABLE POI_CITIES_MATCH 

Здесь %1$I относится к первому параметру после строки, которая является idenifier: rec1; %2$L - второй параметр, являющийся буквальным значением: counter. Я оставляю это для себя, чтобы переработать это с конкатенацией строк до 8.4. Результаты запроса хранятся в нескольких дополнительных переменных, которые затем можно использовать в следующем вызове функции.

И, наконец, у вас было longitude и latitude было отменено. В PostGIS longitude всегда на первом месте.

Смежные вопросы