Как преобразовать процедуру PL / Pg SQL в динамическую c? - PullRequest
2 голосов
/ 16 января 2020

Я пытаюсь написать процедуру plpg sql для выполнения пространственного разбиения таблицы 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';

После успешного тестирования мне нужно преобразовать ее в динамическую c процедуру, в которой я может предоставить имена таблиц в качестве параметров. Я попробовал следующее частичное преобразование, используя format () для внутренней части l oop:

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"

Итак, как я могу преобразовать процедуру Динамо c один? Более конкретно, как я могу использовать тип данных записи (мозаику), возвращаемый для l oop внутри l oop? Обратите внимание, что это работает, когда формат не используется.

Ответы [ 2 ]

2 голосов
/ 16 января 2020

Вы можете использовать EXECUTE ... USING для предоставления параметров в динамический запрос c:

EXECUTE
   format(
      'SELECT r FROM %I WHERE c = $1.val',
      table_name
   )
INTO result_var
USING record_var;

Первый аргумент USING будет использоваться для $1, второй для $2 и т. д.

Подробнее см. в документации .

0 голосов
/ 16 января 2020

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

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$

Вы просто делаете запрос в виде текста, и тогда, где хотите, вы можете его выполнить. Может быть, путем проверки значения result1 внутри оператора If или чего-то подобного.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...