2016-03-22 17 views
0

Ich arbeite an einem Projekt, bei dem der Prozentsatz der Kostenstruktur eines Industrieclusters berechnet wird, der aus den Transportkosten in der Region stammt. Ich habe eine Tabelle für jeden Industriecluster mit der detaillierten Kostenaufschlüsselung (Naics, Menge, inregion_amt), einer Nachschlagetabelle transpo_industries mit allen Transportnativen und einer Übersichtstabelle cluster_costs, die schließlich den Namen jedes Industrieclusters enthalten soll (c_name) die Gesamtkosten (tot_cost) und die Transportkosten innerhalb der Region (inregion_transpo). Die Tabelle enthält bereits alle Branchennamen, die den Tabellennamen für die entsprechenden Industriecluster entsprechen.Syntaxfehler beim Aufruf der plpgsql-Funktion

Da ich mindestens 15 Industrie-Cluster durchlaufen muss und diesen Code möglicherweise mit kleineren Teilmengen der Daten erneut ausführen möchte, versuche ich, eine Funktion zu erstellen. Der folgende Code erstellt die Funktion ohne Fehler, aber wenn ich versuche, es aufzurufen, erhalte ich einen Syntaxfehler ("ERROR: Syntaxfehler bei oder in der Nähe von" clustercosts "SQL-Status: 42601) Ich gehe falsch?

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; 

Eine Version mit Format() gibt mir den gleichen Fehler:

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

fehlt ein Leerzeichen nach dem 'from':' from '|| ... ' –

+1

Starker Hinweis zur Verwendung der format() - Funktion und quote_ident() anstelle der String-Verkettung. – joop

+0

Ich habe die Leerzeichen hinzugefügt (Code oben bearbeitet), aber ich bekomme immer noch den gleichen Fehler. Ich probierte auch eine Version mit format(), bevor ich die String-Verkettung versuchte und hatte die gleichen Probleme –

Antwort

0

Sie haben durch die Tatsache, gebissen worden, dass Sie einfache Anführungszeichen in Zeichenfolge in Anführungszeichen verwenden möchten. Sie können dies unter Verwendung dollar-quoted string constants as explained in the documentation vermeiden.

Das Problem tritt auf, weil Sie ein einzelnes Anführungszeichen innerhalb einer SQL-Anweisung verwenden möchten, da Sie den Wert tblname als Zeichenfolgenkonstante übergeben möchten.

Hier verwende ich $a$ innerhalb der Funktion Körper zu zitieren, mit $$ zitiert:

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; 

Es ist gültig fast jede Kennung zwischen den Dollarzeichen einzufügen und ist ein gemeinsames Muster für die Verschachtelung Anführungszeichen in Funktionen, genau wie in Ihrem Fall.


Beispiel

ich erstellen, um die Tabellen, die Sie beschreiben:

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) 

keine Fehler, ausgeführt SQL.

+0

Ich sehe keine Probleme mit Zitaten in der Frage. Ich nehme an, Sie wissen, dass ['String-Konstanten, die nur durch Whitespace mit mindestens einer Newline getrennt sind, verkettet und effektiv behandelt werden, als wäre die Zeichenkette als eine Konstante geschrieben worden] (http://www.postgresql.org/ docs/aktuelle/interaktive/sql-syntax-lexical.html # SQL-SYNTAX-CONSTANTS) - nach SQL-Standard. –

+0

Ja, genau! Deshalb ist 'where c_name = '|| tblname ||;' nicht sinnvoll - der 'tblname' sollte in Anführungszeichen gesetzt werden, aber der Autor kann kein einfaches Anführungszeichen verwenden, da das String-Quoting diese bereits verwendet. Außerdem ist '||' kein unärer Operator. – hruske

+0

Ja, das letzte '||' muss gehen. Bezeichner benötigen * doppelte Anführungszeichen *, niemals einfache Anführungszeichen. Sollte mit 'quote_ident()' oder mit 'format()' und '% I' gemacht werden. –

1

Ihre Probleme beginnen bereits in der Entwurfsphase. Mit einem richtigen DB-Design würden Sie hierfür zunächst kein dynamisches SQL benötigen.

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

Nicht. Dies sollte mit einer FK-Säule (wie cluster_id) Verweis auf die PK des Tabelle mit Industrie-Cluster (wie industry_cluster) einen einzelner Tisch (wie cluster_details) sein.

Es ist auch fraglich, dass Sie ein berechnetes Aggregat mit Ihrer UPDATE materialisieren. Verwenden Sie stattdessen eine VIEW (oder Funktion), um aktuelle Summen zu erhalten.Ihre Basis Abfrage wäre so etwas wie:

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

Was die Frage gestellt: da der Fehler durch die Funktion Anruf ausgelöst wird und die Fehlermeldung verweist eindeutig den Namen der Funktion, das Problem mit dem Aufruf liegt , die in der Frage fehlt.

Es gibt andere Probleme in Ihrer Funktionsdefinition, wie in den Kommentaren darauf hingewiesen wurde - von denen keiner mit der von Ihnen dargestellten Fehlermeldung in Verbindung steht.

Verwandte Themen