【问题标题】:Syntax for parameterized PostgreSQL function using dynamic SQL使用动态 SQL 的参数化 PostgreSQL 函数的语法
【发布时间】:2021-06-05 11:25:14
【问题描述】:

这段代码:

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);

这在更新单个表时可以正常工作。如何将其转换为动态 SQL 函数,以模式和表为参数?

【问题讨论】:

  • 您正在寻找动态 SQL - ALTER TABLE sch.tab 尝试更改架构 "sch" 中的 "tab" 表,而不是将它们解析为函数的参数。你的函数需要两个字符串,所以你需要调用SELECT create_geom('myschema', 'mytable');
  • 啊。想把它写下来让我接受你的回答吗? :)
  • 我不知道如何正确编写动态SQL。我可能会尝试让函数接受regclass,而不是两个字符串。
  • 感谢您的帮助;让它工作:)

标签: postgresql plpgsql dynamic-sql


【解决方案1】:

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

但是,您还需要连接索引名称的裸表名称,因此我将坚持将 text 分别用于架构和表:

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,无需多次调用。

只需省略 UPDATE 中列的表限定。虽然不加入其他表,但列名是明确的。否则,使用可以是常量的表别名。喜欢:

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

但是在构建索引之前填充列会更聪明。这要快得多,并且可以生成平衡的索引而不会膨胀。所以我切换了命令。

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

也就是说,将具有冗余信息的列添加到表中通常是错误的。 (是什么让您无法更改其中一个?为什么要让表格膨胀?)要么只使用表达式索引而不是上述所有内容:

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

或者从表中删除现在多余的 longlat。这些可以从新的geom 中以低廉的价格即时提取。

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

【讨论】:

    【解决方案2】:

    将查询作为 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');
    

    【讨论】:

    • %I_idx 可能会产生错误的结果;有像%2I这样的位置参数来避免像... tab, tab, tab ...这样的东西
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-13
    • 1970-01-01
    • 2021-12-09
    • 1970-01-01
    • 2015-06-03
    • 1970-01-01
    相关资源
    最近更新 更多