在函数 PLpgSQL 的查询中使用行作为 table
Using a row as a table in a query within a function PLpgSQL
我正在尝试编写一个循环遍历 table 的 plpgsql 函数。在每个循环中,它从 table 中提取一行,将其存储在一条记录中,然后在查询的连接子句中使用该记录。这是我的代码:
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
有没有办法在嵌套循环的查询中将该行用作 table?
我的最终目标是构建一个循环遍历 table 的函数,在每个循环中从 table 中拉出一行。在每个循环中,使用该行计算一个数字 COUNTER,然后根据该行和 COUNTER 执行查询。知道这段代码目前存在很大缺陷,我将其发布在下面以了解我正在尝试做什么:
创建或替换函数 "testfncjh" () RETURNS void
不变的
安全定义者
作为 $dbvis$
宣布
计数器;
table大小整数;
rec1记录;
table姓名文字;
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 数据库。
另外,很抱歉重新发布。我不得不从原始数据中删除一些数据。
我认为您应该能够根据需要使用复合类型。我简化了您的顶级示例并按以下方式使用了复合类型。
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).*)
希望对您有所帮助。
编辑:我应该注意到该函数的作用与上面的问题不同。这只是一个示例,说明如何在查询中将记录用作 table。
您的代码存在一些问题(除了您的逻辑之外)。
最重要的是,您不应将 record
用作 JOIN
中的 table 来源。相反,过滤第二个 table 以查找与 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 之前的字符串连接。查询的结果存储在一些额外的变量中,您可以在接下来的函数调用中使用这些变量。
最后,您将 longitude
和 latitude
颠倒了。在 PostGIS 中 longitude
总是第一位。
我正在尝试编写一个循环遍历 table 的 plpgsql 函数。在每个循环中,它从 table 中提取一行,将其存储在一条记录中,然后在查询的连接子句中使用该记录。这是我的代码:
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
有没有办法在嵌套循环的查询中将该行用作 table?
我的最终目标是构建一个循环遍历 table 的函数,在每个循环中从 table 中拉出一行。在每个循环中,使用该行计算一个数字 COUNTER,然后根据该行和 COUNTER 执行查询。知道这段代码目前存在很大缺陷,我将其发布在下面以了解我正在尝试做什么:
创建或替换函数 "testfncjh" () RETURNS void 不变的 安全定义者 作为 $dbvis$ 宣布 计数器; table大小整数; rec1记录; table姓名文字; 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 数据库。
另外,很抱歉重新发布。我不得不从原始数据中删除一些数据。
我认为您应该能够根据需要使用复合类型。我简化了您的顶级示例并按以下方式使用了复合类型。
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).*)
希望对您有所帮助。
编辑:我应该注意到该函数的作用与上面的问题不同。这只是一个示例,说明如何在查询中将记录用作 table。
您的代码存在一些问题(除了您的逻辑之外)。
最重要的是,您不应将 record
用作 JOIN
中的 table 来源。相反,过滤第二个 table 以查找与 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 之前的字符串连接。查询的结果存储在一些额外的变量中,您可以在接下来的函数调用中使用这些变量。
最后,您将 longitude
和 latitude
颠倒了。在 PostGIS 中 longitude
总是第一位。