我正在尝试编写一个plpgsql过程来执行postGIS表的空间平铺。我可以使用以下过程对表名进行硬编码,从而成功执行该操作。该过程循环遍历tile_table中的图块,并为每个图块剪切area_table并将其插入split_table中。
CREATE OR REPLACE PROCEDURE splitbytile()
AS $$
DECLARE
tile RECORD;
BEGIN
FOR tile IN
SELECT tid, geom FROM test_tiles ORDER BY tid
LOOP
INSERT INTO split_table (id, areaname, ttid, geom)
SELECT id, areaname, tile.tid,
CASE WHEN st_within(base.geom, tile.geom) THEN st_multi(base.geom)
ELSE st_multi(st_intersection(base.geom, tile.geom)) END as geom
FROM area_table as base
WHERE st_intersects(base.geom, tile.geom);
COMMIT;
END LOOP;
END;
$$ LANGUAGE 'plpgsql';
已经成功测试了这一点,现在我需要将其转换为动态过程,在该过程中可以提供表名作为参数。我尝试了以下部分转换,将format()用于循环内部:
CREATE OR REPLACE PROCEDURE splitbytile(in_table text, grid_table text, split_table text)
AS $$
DECLARE
tile RECORD;
BEGIN
FOR tile IN
EXECUTE format('SELECT tid, geom FROM %I ORDER BY tid', grid_table)
LOOP
EXECUTE
FORMAT(
'INSERT INTO %1$I (id, areaname, ttid, geom)
SELECT id, areaname, tile.tid,
CASE WHEN st_within(base.geom, tile.geom) THEN st_multi(base.geom)
ELSE st_multi(st_intersection(base.geom, tile.geom)) END as geom
FROM %2$I as base
WHERE st_intersects(base.geom, tile.geom)', split_table, in_table
);
COMMIT;
END LOOP;
END;
$$ LANGUAGE 'plpgsql';
但是会引发错误
missing FROM-clause entry for table "tile"
那么,如何将程序转换为动态程序?更具体地说,如何在循环内使用for循环返回的记录数据类型(平铺)?请注意,它在不使用格式时有效。
答案 0 :(得分:2)
您可以使用EXECUTE ... USING
为动态查询提供参数:
EXECUTE
format(
'SELECT r FROM %I WHERE c = $1.val',
table_name
)
INTO result_var
USING record_var;
USING
的第一个参数将用于$1
,第二个参数将用于$2
,依此类推。
有关详细信息,请参见the documentation。
答案 1 :(得分:-1)
我个人使用某种方式来创建动态函数。通过合并和执行功能。您也可以这样做。
CREATE OR REPLACE FUNCTION splitbytile()
RETURNS void AS $$
declare
result1 text;
table_name text := 'test_tiles';
msi text := '+7 9912 231';
msi text := 'Hello world';
code text := 'code_name';
_operator_id integer := 2;
begin
query1 := 'SELECT msisdn from ' || table_name || ' where msisdn = ''' || msi::text ||''';';
query2 := 'INSERT INTO ' || table_name || '(msisdn,usage,body,pr_code,status,sent_date,code_type,operator_id)
VALUES( ''' || msi::text || ''',' || true || ',''' || _body::text || ''',''' || code::text || ''',' || false || ',''' || time_now || ''',' || kod_type || ',' || _operator_id ||');';
execute query1 into result1;
execute query2;
END;
$function$
您只需以文本形式进行查询,然后在任何您希望执行的地方进行查询。也许可以通过检查If语句或类似内容中的result1值来实现。