使用动态 SQL 的参数化 PostgreSQL 函数的语法

Syntax for parameterized PostgreSQL function using dynamic SQL

此代码:

ALTER TABLE myschema.mytable add column geom geometry (point,4326);
CREATE INDEX mytable_idx on myschema.mytable using GIST(geom);
UPDATE myschema.mytable set geom = st_setsrid(st_point(mytable.long, mytable.lat), 4326);

这在更新单个 table 时工作正常。您如何将其转换为动态 SQL 函数,以架构和 table 作为参数?

将您的查询作为 SQL 模板并使用 format 函数作为标识符:

CREATE OR REPLACE FUNCTION public.create_geom(sch text, tab text)
RETURNS void language plpgsql AS $body$
DECLARE
 DYNSQLA constant text := 'ALTER TABLE %I.%I add column geom geometry (point,4326)';
 DYNSQLB constant text := 'CREATE INDEX %I_idx on %I.%I using GIST(geom);';
 DYNSQLC constant text := 'UPDATE %I.%I set geom = st_setsrid(st_point(%I.long, %I.lat), 4326)';
BEGIN
    execute format(DYNSQLA, sch, tab);
    execute format(DYNSQLB, tab, sch, tab);
    execute format(DYNSQLC, sch, tab, tab, tab);
END;
$body$;

SELECT create_geom('myschema','mytable');

由于函数输入必须是现有的 table,最简单的 安全 方法是使用 regclass 输入参数,如下所示:

  • Table name as a PostgreSQL function parameter

但是,您还需要连接索引名称的裸 table 名称,因此我将坚持使用 text 作为架构,并分别使用 table:

CREATE OR REPLACE FUNCTION create_geom(_sch text, _tab text)
  RETURNS void
  LANGUAGE plpgsql AS
$func$
BEGIN
   EXECUTE format(   
'ALTER TABLE %1$I.%2$I ADD COLUMN geom geometry(POINT,4326);
UPDATE %1$I.%2$I SET geom = st_setsrid(st_point(long, lat), 4326);
CREATE INDEX %3$I ON %1$I.%2$I USING gist(geom);'
   , _sch, _tab
   , _tab || '_geom_gist_idx');
END
$func$;

通话:

SELECT create_geom('myschema', 'mytable');

使用单个 EXECUTE,无需多次调用。

只需省略 table-对 UPDATE 中列的限定。虽然不加入额外的 table,但列名是明确的。否则,使用 table 别名,它可以是常量。喜欢:

UPDATE %1$s AS x SET geom = st_setsrid(st_point(x.long, x.lat), 4326);

但是在构建索引之前填充列会更明智。这要快得多,并且会产生一个没有膨胀的平衡索引。所以我切换了命令。

请注意我是如何先连接索引名称 (_tab || '_geom_gist_idx'),然后 然后 根据需要使用 %3$I 双引号。这是安全的方法。 %I_idx 之类的东西因非标准名称而失败。

就是说,将具有冗余信息的列添加到 table 通常是错误的。 (是什么阻止你改变一个或另一个?为什么要膨胀 table?)要么只使用表达式索引而不是以上所有内容:

CREATE INDEX ON myschema.mytable USING gist (st_setsrid(st_point(long, lat), 4326));

或者从 table 中删除现在多余的 long & lat。这些可以从新的 geom 中廉价地即时提取。

或者,如果您需要所有列(出于特殊性能原因?),请考虑使用生成的列。参见:

  • Computed / calculated / virtual / derived columns in PostgreSQL