【问题标题】:syntax error when calling plpgsql function调用 plpgsql 函数时出现语法错误
【发布时间】:2016-03-24 12:41:56
【问题描述】:

我正在开展一个项目,该项目涉及计算来自区域内运输成本的产业集群成本结构的百分比。我将为每个行业集群提供一个表格,其中包含详细的成本明细(naics、金额、inregion_amt)、一个包含所有运输 naics 的查找表transpo_industries,以及一个汇总表cluster_costs,我希望最终包含每个行业集群的名称(c_name)、总成本(tot_cost)和区域内运输成本(inregion_transpo)。该表已经填充了所有行业名称,这些名称与相应行业集群的表名称相匹配。

由于我需要运行至少 15 个行业集群,并且可能希望使用较小的数据子集重新运行此代码,因此我正在尝试创建一个函数。下面的代码创建了没有错误的函数,但是当我尝试调用它时,我得到一个语法错误(“ERROR: syntax error at or near "clustercosts" SQL state: 42601")

谁能帮忙指出我哪里出错了?

create or replace function clustercosts(tblname text) RETURNS void
AS $$
BEGIN
EXECUTE 'update cluster_costs set tot_cost= (select sum(amount) from '||tblname||'), inregion_transpo = (select sum(inregion_amt) from '||tblname||', transpo_industries where '||tblname||'.naics=transpo_industries.naics) where c_name='||tblname||;
END;
$$ Language plpgsql;

使用 format() 的版本给了我同样的错误:

CREATE OR REPLACE FUNCTION udate_clustercosts(tblname text)
  RETURNS void AS
$BODY$
BEGIN
EXECUTE format(
'update cluster_costs'
'set tot_cost= (select sum(amount)from %I),'
'inregion_transpo = (select sum(inregion_amt) from %I, transpo_industries where %I.naics=transpo_industries.naics)'
'where c_name=%I',tblname);
END;
$BODY$
  LANGUAGE plpgsql;

【问题讨论】:

  • from 后面少了一个空格:from '||...
  • 强烈建议使用 format() 函数和 quote_ident() 而不是字符串连接。
  • 我添加了空格(上面编辑的代码),但我仍然遇到同样的错误。在我尝试字符串连接之前,我实际上也尝试了一个带有 format() 的版本并且遇到了同样的问题
  • 尝试将'where c_name=%I'更改为'where c_name=%L'
  • 其他选项:where c_name='''||tblname||'''';

标签: postgresql plpgsql


【解决方案1】:

您的问题始于设计阶段。有了适当的数据库设计,您就不需要动态 SQL。

我会为每个产业集群准备一张桌子......

不要。这应该是一个单个表(如cluster_details),其FK 列(如cluster_id)引用列出行业集群的表的PK(如industry_cluster)。

使用UPDATE 实现计算聚合也是值得怀疑的。改用VIEW(或函数)来获取当前总和。您的基本查询类似于:

SELECT ic.*
     , sum(cd.amount) AS sum_amount
     , (SELECT sum(inregion_amt)
        FROM   transpo_industries
        WHERE  naics = cd.naics) AS sum_inregion_amt
FROM   industry_cluster ic
LEFT   JOIN cluster_details cd USING (cluster_id)
WHERE  ic.name = 'Cluster 1';

关于问的问题:由于错误是由函数call触发的,而且错误信息中明确引用了函数名,所以问题出在调用上,问题中缺少。

您的函数定义中还有其他问题,正如 cmets 中所指出的 - 这些都与您提供的错误消息无关。

【讨论】:

    【解决方案2】:

    你已经被一个事实所困扰,你想在带引号的字符串中使用单引号。您可以使用dollar-quoted string constants as explained in the documentation 来避免这种情况。

    问题出现是因为您想在 SQL 语句中使用单引号,因为您想将 tblname 的值作为字符串常量传递。

    这里我用$a$在函数体内引用,用$$引用:

    create or replace function clustercosts(tblname text) RETURNS void
    AS $$
    BEGIN
    EXECUTE $a$ update cluster_costs set tot_cost= (select sum(amount) from $a$ || tblname || $a$), inregion_transpo = (select sum(inregion_amt) from $a$ || tblname || $a$, transpo_industries where $a$ || tblname || $a$.naics=transpo_industries.naics) where cluster_costs.c_name='$a$ || tblname || $a$'$a$;
    END;
    $$ language plpgsql;
    

    在美元符号之间插入几乎任何标识符都是有效的,并且是在函数中嵌套引号的常见模式,与您的情况完全相同。


    示例

    我创建了您描述的表格:

    create table tblname (naics int, amount int, inregion_amt int);
    create table transpo_industries (naics int);
    create table cluster_costs (c_name text, tot_cost int, inregion_transpo int);
    
    testdb=> SELECT clustercosts('tblname');
     clustercosts 
    --------------
    
    (1 row)
    

    没有错误,已执行 SQL。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-12-11
    • 2023-02-05
    • 1970-01-01
    • 2018-02-10
    • 2015-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多