verschachtelte Case Abfrage

Hallo,

ich habe folgendes Problem.
Ich bin totaler Anfänger was stored procedures angeht, jedoch relativ geübt, was Delphi und VBA angeht, sprechend ist mein Code ent-standen…
Wie es scheint, wird die gesamte Funktionsbezeichnung von Postgres selber erstellt. Ich habe jedoch noch nicht verstanden, inwieweit die EIngangs oder Ergebnisargumente noch in den Deklarationen stehen müssen. Unklar ist mir auch noch inwieweit If - then Strukturen oder ähnliche Programm Strukturen problemlos neben SQL Abfragen stehen können.

Könnte mir jemand helfen, den Syntax in folgender verschachtelter Case-Abfrage so zu korrigieren, dass es dem Datenbank PL-PG- SQL konform ist ? Irgendwie kriege ich immer eine Fehlermeldung. Zwar gibt es realtiv viele Info’s zu stored procedures PL-PG-SQL im Internet, aber weniger zu PL-Pg-SQL als zu den anderen, so dass ich mir nicht sicher bin, ob da nicht auch was durcheinander geraten ist:

[size=100][font=Calibri]CREATE FUNCTION is_valid(pconreac, pconpro: text) RETURNS boolean AS [/font][/size]
[font=Lucida Console]declare @Return boolean[/font]
[size=100][font=Calibri]BEGIN[/font][/size]
[size=100][font=Calibri]Select pcon.pcontype as typepro[/font][/size]
[size=100][font=Calibri]from pcon[/font][/size]
[size=100][font=Calibri]where (pcon.symbol = pconpro);[/font][/size]
[size=100][font=Calibri]case[/font][/size]
[size=100][font=Calibri]  when (pcon.typepro = 'SecondaryMaster')[/font][/size]
[size=100][font=Calibri]   then [/font][/size]
[size=100][font=Calibri]    begin[/font][/size]
[size=100][font=Calibri]    Select pcon.pcontype as typereac[/font][/size]
[size=100][font=Calibri]    from pcon[/font][/size]
[size=100][font=Calibri]    where (pcon.symbol = pconreac);[/font][/size]
[size=100][font=Calibri]    case[/font][/size]
[size=100][font=Calibri]    when (pcon.typereac = 'PrimaryMaster')[/font][/size]
[size=100][font=Calibri]    then   [/font][/size][font=Lucida Console]@return = [/font][size=100][font=Calibri]true;[/font][/size]
[size=100][font=Calibri]    else[/font][/size]
[font=Calibri][size=100]    [/size][/font][font=Lucida Console]@return = [/font][size=100][font=Calibri]false;[/font][/size]
[size=100][font=Calibri]    end case;[/font][/size]
[size=100][font=Calibri] when (pcon.typepro = 'Product')[/font][/size]
[size=100][font=Calibri]   then [/font][/size]
[size=100][font=Calibri]    begin[/font][/size]
[size=100][font=Calibri]    Select pcon.pcontype as typereac[/font][/size]
[size=100][font=Calibri]    from pcon[/font][/size]
[size=100][font=Calibri]    where (pcon.symbol = pconreac);[/font][/size]
[size=100][font=Calibri]    case[/font][/size]
[size=100][font=Calibri]    when (pcon.typereac = 'PrimaryMaster')[/font][/size]
[size=100][font=Calibri]    then   [/font][/size][font=Lucida Console]@return = [/font][size=100][font=Calibri]true;[/font][/size]
[size=100][font=Calibri]    when (pcon.typereac = 'SecondaryMaster')[/font][/size]
[size=100][font=Calibri]    then   [/font][/size][font=Lucida Console]@return = [/font][size=100][font=Calibri]true;[/font][/size]
[size=100][font=Calibri]    else[/font][/size]
[font=Calibri][size=100]    [/size][/font][font=Lucida Console]@return = [/font][size=100][font=Calibri]false;[/font][/size]
[size=100][font=Calibri]    end case;[/font][/size]
[size=100][font=Calibri]when (pcon.typepro = 'MineralsSolids')[/font][/size]
[size=100][font=Calibri]   then [/font][/size]
[size=100][font=Calibri]    begin[/font][/size]
[size=100][font=Calibri]    Select pcon.pcontype as typereac[/font][/size]
[size=100][font=Calibri]    from pcon[/font][/size]
[size=100][font=Calibri]    where (pcon.symbol = pconreac);[/font][/size]
[size=100][font=Calibri]    case[/font][/size]
[size=100][font=Calibri]    when (pcon.typereac = 'PrimaryMaster')[/font][/size]
[size=100][font=Calibri]    then   [/font][/size][font=Lucida Console]@return = [/font][size=100][font=Calibri]true;[/font][/size]
[size=100][font=Calibri]    when (pcon.typereac = 'SecondaryMaster')[/font][/size]
[size=100][font=Calibri]    then   [/font][/size][font=Lucida Console]@return = [/font][size=100][font=Calibri]true;[/font][/size]
[size=100][font=Calibri]    else[/font][/size]
[font=Calibri][size=100]    [/size][/font][font=Lucida Console]@return = [/font][size=100][font=Calibri]false;[/font][/size]
[size=100][font=Calibri]    end case;[/font][/size]
[size=100][font=Calibri] else[/font][/size]
[font=Lucida Console]@return = [/font][size=100][font=Calibri]false;   [/font][/size]
[size=100][font=Calibri][/font][/size] 
[size=100][font=Calibri]case end;[/font][/size]
[size=100][font=Calibri][size=100][font=Calibri]$$ LANGUAGE SQL;[/font][/size][/font][/size]
[size=100][font=Calibri]

[/font][/size]
In dem Code geht es darum, dass in einer (hier nicht näher erwähnten Tabelle reactions) Einträge gemacht werden, die aus einer anderen Tabelle pcon entnommen werden und nur bestimmte charakteristiken besitzen dürfen. Wenn z.B. das Reactionendsprodukt pconpro den Status ‘Secondary-Master’ -species hat, dann werden als Reaktionsausgangsprodukte nur Einträge mit dem Status ‘PrimaryMaster’ zugelassen. Entsprechende Einschränkungen gelten auch für andere Spezies. Die Procedure soll dann in einem Trigger zu der Tabelle Reactions aufgerufen werden, wobei die erwähnten Variablen pconPro dann dort New.PconProduct und pconReac dem Eintrag New.PconReactant entsprechen sollen.
Ich kenne die Postgres-SQL Dokumentation und habe 2 bis 3 Tutorials mir angeschaut, aber die betrafen entweder ganz andere Themen, waren zu einfach oder nicht ausführlich genug.

Kann jemand neben Tipps zur Lösung dieser Aufgabe ein gutes Gratis-Tutorial empfehlen oder, falls nicht vermeidbar, auch ein wirklich gutes (und günstiges) Buch, das von ganz einfachen Anfängen zu komplexen Beispielen führt ?

Vielen Dank für jede Hilfe.

ThommyW

Also. Was meinst Du mit ‘gesamte Funktionsbezeichnung von Postgres selber erstellt’?.

Controllstrukturen: Was ist so schwer, mal die Doku zu lesen?
PostgreSQL: Documentation: Manuals: PostgreSQL 8.3: Control Structures
Ein CASE wirst Du dort nicht finden, nur hier: Control Structures

Mit anderen Worten: entweder Dein CASE in IF … THEN umschreiben oder auf 8.4 warten.

Außerdem: diese Dinge hast Du nicht in SQL, sondern nur in PLPGSQL. Also solltest Du Deine Procs auch in dieser Sprache schreiben.



Andreas

Hallo Andreas,

zumindest habe ich meinen Projektleiter jetzt klargemacht, dass, auch wenn es um Trigger geht, es am sinnvollsten ist, die Tests als Stored procedure zu formulieren.

—Controllstrukturen: Was ist so schwer, mal die Doku zu lesen?
PostgreSQL: Documentation: Manuals: PostgreSQL 8.3: Control ----- Structures
----Ein CASE wirst Du dort nicht finden, nur hier: Control Structures


Da Du den Code sicherlich aufmerksam gelesen hast, hast Du sicherlich bemerkt, dass ich “end case” und die “when … then” Struktur verwendet habe. Dies rührt daher, dass ich mir einige procedures von postgresSQL angesehen habe… wenn auch nicht nur in der doku.
In der Tat setzen wir PostgresSQL 8.1.5 ein, danke für den Hinweis. Mir war nicht aufgefallen, dass da so gravierende Unterschiede sind. Ein Upgrade auf 8.3 oder 8.4 könnte bei der nächsten Servermigration erfolgen, aber das wird noch dauern…

Und ich weiss nicht wieso dass falsch rüber gekommen ist, aber
“procedure in PL pg SQL schreiben”
hey, … das ist genau das was ich will und dachte bereits weitgehend getan zu haben, wenn auch mit Fehlern…

Ok, dann schreibe ich sie mal nach if … then um…

Schon mal danke

Thomas

Nein. Nur flüchtig überflogen, da schon in der 2. Zeile mehr als nur ein Fehler ist.


hast Du sicherlich bemerkt, dass ich “end case” und die “when … then” Struktur verwendet habe.

Ja.

Dies rührt daher, dass ich mir einige procedures von postgresSQL angesehen habe… wenn auch nicht nur in der doku.

Ich finde ja, daß man insbesondere bei Syntaxfragen erstmal NUR die Doku befragen sollte. Warum? Stell Dir vor, ein Anfänger will seine ersten Versuche mit PG machen und liest Dein Beitrag. Es wäre fatal, würde er annehmen, dies würde so (von der Syntax her) funktionieren.

In der Tat setzen wir PostgresSQL 8.1.5 ein, danke für den Hinweis. Mir war nicht aufgefallen, dass da so gravierende Unterschiede sind. Ein Upgrade auf 8.3 oder 8.4 könnte bei der nächsten Servermigration erfolgen, aber das wird noch dauern…

Oh, zwischen den Majer-Versionen von PG passiert schon so einiges…

Und ich weiss nicht wieso dass falsch rüber gekommen ist, aber
“procedure in PL pg SQL schreiben”
hey, … das ist genau das was ich will und dachte bereits weitgehend getan zu haben, wenn auch mit Fehlern…

PostgreSQL: Documentation: Manuals: PostgreSQL 8.3: CREATE FUNCTION , Parameter langname.



Andreas

Hallo,

Nach einiger Nacharbeitung des vorgenannten Codes bin ich zu folgendem Code gelangt:

[color=black][color=black][font=Times New Roman][color=black][font=Times New Roman]DECLARE passed BOOLEAN;[/font][/color][/font][/color][/color]
[color=black][color=black][font=Times New Roman][font=Times New Roman]BEGIN[/font][/font][/color][font=Times New Roman]
[color=black][font=Times New Roman]Select pcon.pcontype as typepro[/font][/color]
[color=black][font=Times New Roman]from pcon[/font][/color]
[color=black][font=Times New Roman]where (pcon.symbol = pconpro);[/font][/color]
 
[color=black][font=Times New Roman]if  (typepro = 'SecondaryMaster')   then [/font][/color]
[color=black][font=Times New Roman]begin   [/font][/color]
[color=black][font=Times New Roman]  Select pcon.pcontype as typereac[/font][/color]
[color=black][font=Times New Roman]  from pcon[/font][/color]
[color=black][font=Times New Roman]  where (pcon.symbol = pconreac);[/font][/color]
 
[color=black][font=Times New Roman] if  (typereac = 'PrimaryMaster') then [/font][/color]
[color=black][font=Times New Roman]  passed: = true;[/font][/color]
[color=black][font=Times New Roman] else[/font][/color]
[color=black][font=Times New Roman]  passed := false;[/font][/color]
[color=black][font=Times New Roman] end if;[/font][/color]
[color=black][font=Times New Roman]end;[/font][/color]
 
[color=black][font=Times New Roman]if (typepro = 'Product') or (typepro = 'MineralsSolids')  then [/font][/color]
[color=black][font=Times New Roman]begin[/font][/color]
[color=black][font=Times New Roman]   Select pcon.pcontype as typereac[/font][/color]
[color=black][font=Times New Roman]   from pcon[/font][/color]
[color=black][font=Times New Roman]   where (pcon.symbol = pconreac);[/font][/color]
 
[color=black][font=Times New Roman]  if  (typereac = 'PrimaryMaster')  or  (typereac = 'SecondaryMaster') then   [/font][/color]
[color=black][font=Times New Roman]    passed := true;[/font][/color]
[color=black][font=Times New Roman]   else[/font][/color]
[color=black][font=Times New Roman]   passed : = false;[/font][/color]
[color=black][font=Times New Roman]  end if;[/font][/color]
 
[color=black][font=Times New Roman]end;[/font][/color]
[/font][/color]

liefert folgenden " Funktionstext und Fehlermeldung:

SQL Fehler:
FEHLER: Fehler »syntax error« am Ende der Eingabe at character 781
In der Anweisung:

   
CREATE FUNCTION "IsvalidEntry" (IN pconpro text,IN pconreac text) as '
[color=black][color=black][font=Times New Roman][color=black][font=Times New Roman]DECLARE passed BOOLEAN;[/font][/color][/font][/color][/color]
 (obiger Code mit verdoppelten Hochkommas)
LANGUAGE "plpgsql"

Sicher könnte ich auch noch ein paar Stunden mehr daran rumprobieren, aber das erscheint mir uneffectiv. Ein Buch zu dieser Postgres-SQL Version wurde eher abgelehnt, da ja sowieso eine neue Version für irgendwann geplant ist. Der Fehler taucht angeblich an einer Stelle auf, die jedoch gar nicht existiert, da die Anzahl der Zeichen kleiner ist als die angegebene Stelle…
was mich zu dem Schluss verleitet, dass entweder
kein Ende gefunden wird oder er irgendein Zeichen vermisst und dieses bis zur letzten Zeile sucht…
Das Einzige was mir aufgefallen ist, besteht in dem nicht vorhandenem
Bezeichner für das Boolean -Ergebnis: returns boolean as …
danach kommt gar nichts, jedoch sehe ich nicht wie ich das ändern kann, da

  1. die gesamte Funktionsbezeichnung aus den Einträgen bei der Funktionserstellung entsteht, wo bei mir kein Feld mit einem verfügbarem Eintrag ist,
  2. bei Reinkopieren und Modifikation dieser erzeugten Zeile gar nichts mehr funktioniert, da diese Zeile dann auch noch mal erzeugt wird und zu Chaos führt (einer meiner ersten Fehler, da das nirgends geschrieben steht).

Ferner ist mir aufgefallen:
Wenn ich alles eingetragen habe, sieht meine Vorgabe etwa so aus (Nach x Versuchen eine Graphik o. ä. einzufügen, nun die Beschreibung per Schrift):

Block: Name Liefert Sprache
“IsValidEntry” “(leeresFeld1)” “Boolean” “(leeres Feld2)” “PLPGSQL”

Block: Mode Name Type (Block zum hinzufügen)
“IN” “pconpro” “Text”
“IN” “pconreac” “Text”

leeres Feld1: “Set of” auswählbar
leeresFeld2 nur “[]” auswählbar


Das Feld links neben der Sprache (PL-PG SQL) ist mir zwar nicht ganz klar, aber ich hätte dort irgendwo den Bezeichner hinter dem “as” gesucht…

Wenn ich dann versuche, die Funktion zu erstellen und ein Fehler auftritt, dann ändert sich die Vorgabe zu folgendem Bild:


Block: Name Liefert Sprache
“IsValidEntry” “(leeresFeld1)” “Boolean” “(leeres Feld2)” “PLPGSQL”

Block: Mode Name Type (Block zum hinzufügen)
“(leeresFeld3)” “pconpro” “(leeresFeld45)”
“(leeresFeld3)” “pconpro” “(leeresFeld45)”

leeres Feld1: “Set of” auswählbar
leeresFeld2: nur “[]” auswählbar
leeresFeld3: nur " " auswählbar
leeresFeld45: 2 dicht nebeneinander liegende leere Felder, die nur etwa 3 mm breit sind, nur Leerzeichen auswählbar (statt Text)

Diese sinnlose neue Vorgabe führt dann bei einem neuen Erstellungsversuch zum Fehler:
“Typ p schon definiert.”

Also muss ich alle Argumente neu eintragen, mindestens bei jedem 2.Mal…

Weiss jemand woher das kommt ?

Kann mir jemand den Fehler im Code sagen ?

Vielen Dank im voraus…

Thomas

Ist leider alles schwer nachvollziehbar bei Dir…

Wenn Du den Body der Funktion mit ’ einleitest (und kein Dollar-Quoting verwendest) mußt Du Stringst in doppelten ’ quoten, also zwei mal das ’ drum herum.

...
test'#   end if;
test'#
test'# end;
test'# ' LANGUAGE "plpgsql";
ERROR:  syntax error at or near "SecondaryMaster"
LINE 8: if  (typepro = 'SecondaryMaster')   then

Bitte verwende für Code passende Code-Tags, also [ auf, dann code, dann ]. Und wenn fertig, [, dann /code, und ]. Und Funktionsdefinitionen bitte komplett angeben.

Das ‘Begin’ nach dem IF ist übrigens auch falsch.

Ich schlage Dir vor, Du schaust nun endlich mal in die Doku und versuchst mal, ein Beispiel von dort fehlerfrei abzutippen.


Andreas

Zu dieser Orgie kann ich nur folgendes sagen:

Nehme eine Editor Deines geringsten Mißtrauens und schreibe Deine Funktion damit. Speichere das ab. Und in psql, (das ist der Kommandozeilen-Client von PG) verwendest Du ganz simpel \i <Deine_Datei>, um das einzulesen. Wenn dann ein Fehler kommt, gehst Du zurück zu Start, ähm, Editor.

Mag sein, daß das alles auch in PGAdminIII geht. Aber das ist (mir zumindest) deutlich schwerer damit und ich bin echt zu faul, die Bedienung dieser GUI zu erlernen und zu erlernen, was ich in welcher Reihenfolge drücken muß, um das zu erreichen, was ich will, und von dem ich weiß, wie es geht.

Andreas, viele Terminals unter KDE nutzend…

Was akretschmer dir sagen möchte: speichere deine Funktion in einer Datei und lies diese Datei direkt in die Datenbank ein. Das erleichtert die Fehlersuche, da du den vollständingen Funktionstext im Editor deines geringsten Misstrauens vorliegen hast. pgAdminIII ist dafür etwas äh ungeeignet.

Als zweites würde ich dir raten: probiere das ganze Stück für Stück. Du schreibst große und umfangreiche Funktionen (ok, für mich sind die nicht groß, aber für dich) und stolperst dabei über jeden Fehler. Wenn du vorn anfängst und zuerst mal Kleinigkeiten probierst und siehst wie die funktionieren, kommst du sicherlich schneller voran.

Und wie akretschmer auch schon gesagt hat: da verstecken sich schon diverse Fehler gleich am Anfang. Nur ist hier ehrlich gesagt niemand dafür da, dir dein Debugging abzunehmen und/oder dir die Sprache beizubringen.