如何将PL / PgSQL过程转换为动态过程?

时间:2020-01-16 00:25:25

标签: postgresql postgis plpgsql

我正在尝试编写一个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循环返回的记录数据类型(平铺)?请注意,它在不使用格式时有效。

2 个答案:

答案 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值来实现。