调用plpgsql函数时出现语法错误

时间:2016-03-22 16:56:21

标签: postgresql plpgsql

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

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

任何人都可以帮助指出我出错的地方吗?

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;

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

urlConnection.setRequestProperty("Accept","*/*");

2 个答案:

答案 0 :(得分: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';

至于提出的问题:由于错误是由函数 调用 触发的,并且错误消息明确引用了函数名称,问题在于调用,在问题中缺失。

您的函数定义中还存在其他问题,正如评论中指出的那样 - 这些问题都与您提供的错误消息无关。

答案 1 :(得分:0)

你一直被这个事实所困扰,你想在引用的字符串中使用单引号。您可以使用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已执行。