2016-03-22 15 views
0

私は、地域内の輸送費に由来する産業クラスターのコスト構造のパーセントを計算するプロジェクトに取り組んでいます。詳細なコスト内訳(naics、amount、inregion_amt)、すべての交通機関naicsのルックアップテーブルtranspo_industries、最終的に各業種のクラスタ名(c_name)を含めるサマリーテーブルcluster_costsを持つ各業種クラスタごとに1つの表があります。 、総コスト(tot_cost)、および地域内輸送コスト(inregion_transpo)を含む。このテーブルには、既に対応する業界クラスタのテーブル名と一致するすべての業界名が入力されています。plpgsql関数を呼び出すときに構文エラーが発生する

私は少なくとも15の産業クラスターを実行する必要があり、データのより小さいサブセットでこのコードを再実行したいと思うので、私は関数を作成しようとしています。次のコードはエラーなしで関数を作成しますが、私はそれを呼び出そうとすると文法エラーが発生します( "ERROR:構文エラー"または近くの "clustercosts" SQLステート: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; 

フォーマットを使用したバージョンは()私に同じエラーを与える:

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; 
+0

'from'の後に空白がありません:' from '|| ... ' –

+1

文字列連結の代わりにformat()関数とquote_ident()を使用するようにアドバイスします。 – joop

+0

スペースを追加しましたが(上記で編集したコード)、私はまだ同じエラーが発生しています。私は実際に文字列の連結を試み、同じ問題を抱えていた前に、format()でバージョンを試しました。 –

答えて

0

あなたが引用符で囲まれた文字列内の単一引用符を使用することを、事実に噛まれています。 dollar-quoted string constants as explained in the documentationを使用することを避けることができます。

文字列定数としてtblnameの値を渡す必要があるため、SQL文内で一重引用符を使用するため、問題が発生します。

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; 

それはまったく同じように、ドル記号の間に、ほぼすべての識別子を挿入するために有効だと機能で営巣引用符のための一般的なパターンです。ここ

私は$$で引用され、関数本体内引用する$a$を使用しますあなたの場合。実行

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:


例は、私はあなたが記述のテーブルを作成します。

+0

私は質問の引用符で問題を参照してくださいしないでください。私はあなたが[''少なくとも1つの改行で空白で区切られた文字列定数が連結され、その文字列が1つの定数として記述されているかのように効果的に扱われていることを認識しています」](http://www.postgresql.org/ docs/current/interactive/sql-syntax-lexical.html#SQL-SYNTAX-CONSTANTS) - SQL標準に準拠しています。 –

+0

はい、まさに!だからこそ 'c_name = '|| tblname ||;'は意味をなさない - なぜなら 'tblname'は引用符で囲まれなければならないが、引用符で引用符を使用しているので、一重引用符を使うことはできない。また、 '||'は単項演算子ではありません。 – hruske

+0

はい、最後の '||'は行かなければなりません。識別子には二重引用符*が必要であり、一重引用符は必要ありません。 'quote_ident()'または 'format()'と '%I'で行う必要があります。 –

1

問題は設計段階から始まります。適切なDB設計では、このために動的SQLは必要ありません。

I'll have one table for each industry cluster ...

Do not。これはのような産業クラスターをリストしたテーブルのPKを参照するFK列(cluster_idなど)を持つ単一テーブル(cluster_detailsなど)である必要があります。

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

:何かのようにあなたのベースのクエリは次のようになりますこれは質問には欠けている。

コメントにも指摘されているように、関数定義には他にも問題があります - いずれもあなたが提示したエラーメッセージに関連していません。