在函数PLpgSQL中的查询中使用行作为表

时间:2016-03-02 22:14:17

标签: postgresql plpgsql postgresql-8.2

我正在尝试编写一个循环遍历表的plpgsql函数。在每个循环中,它从表中提取一行,将其存储在记录中,然后在查询的join子句中使用该记录。这是我的代码:

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;

每次运行时,都会出现以下错误:

  

错误:找不到数据类型记录的数组类型

有没有办法在嵌套循环中将该行用作查询中的表?

我的最终目标是构建一个循环遍历表的函数,在每个循环中从该表中拉出一行。在每个循环中,使用该行计算数字COUNTER,然后根据行和COUNTER执行查询。知道这段代码目前存在很大缺陷,我将在下面发布,以便了解我想要做的事情:

创建或替换功能“testfncjh”()RETURNS void       IMMUTABLE       安全定义者     AS $ dbvis $     宣布             反int;             tablesize int;             rec1记录;             tablename文本;             rec2记录;     BEGIN

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数据库上运行。

另外,抱歉重新发布。我不得不从原文中删除一些数据。

2 个答案:

答案 0 :(得分:0)

我认为您应该能够根据需要使用复合类型。我简化了您的顶级示例,并按以下方式使用了复合类型。

LANGUAGES = (
    ('sr-latn', 'Srpski'),
    ('en', 'English'),
)

主要更改为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;

希望它有所帮助。

编辑:我应该注意到该函数与上面的问题没有做同样的事情。这只是一个如何在记录中将记录用作表格的示例。

答案 1 :(得分: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是指字符串后面的第一个参数,它是一个标识符:rec1; %2$L是第二个参数,是一个文字值:counter。我把它留给自己重新处理到8.4之前的字符串连接。查询的结果存储在一些其他变量中,然后您可以在以下函数调用中使用它们。

最后,您longitudelatitude被撤消了。在PostGIS longitude中始终是第一位的。