View Full Version : embeddet SQL, Lib variable setzen
Die Frage, wie man Werte aus einem dynamischen SQL herauskitzeln kann, wurde aber nicht beantwortet.
D #SQL S 5000A VARYING
*
D #LIB S 10A INZ('QTEMP')
D #FILE S 10A INZ('TEST')
*
D #Anz1 S 10P 0
/FREE
#SQL = 'VALUES( +
SELECT COUNT(*) FROM ' + %TRIMR(#LIB) + '/' +
%TRIMR(#FILE) +
') +
INTO ?';
EXEC SQL PREPARE Stmt1 FROM :#SQL;
EXEC SQL EXECUTE Stmt1 USING :#Anz1;
/END-FREE
von Scott Klement abgeschaut; z.B. hier noch komplexer:
https://www.ibm.com/developerworks/community/forums/html/topic?id=25503446-ca6f-4fa4-a628-94cd018d1560
Wenn du mein obiges (von Dieter korrigiertes) Beispiel anschaust, siehst du das sehr wohl.
Nur mit dem Unterschied, dass per Cursor Resultsets und mehr als 1 Wert übergeben werden können.
So verfahre ich z.B. bei embedded SQL via ArdGate um Daten aus Oracle oder SQL-Server direkt im Programm zu erhalten.
Scotts Beispiele aus dem Link beschränken sich da auf 1 Satz per Values, was einem "select blabla into .... from ..." entspricht.
Scotts Beispiele aus dem Link beschränken sich da auf 1 Satz per Values, was einem "select blabla into .... from ..." entspricht.
Wenn ein SET-Statement in Verbindung mit einem SELECT-Statement ausgeführt wird, muss genau eine Zeile zurückkommen. Das war die Ausgangssituation!
Wenn man das Ganze dynamisch machen möchte bzw. muss (weil die Tabelle oder Bibliothek flexibel gehalten werden müssen), kann man entweder
ein VALUES ... INTO Statement dynamisch zusammensetzen und dann mit PREPARE und EXECUTE ausführen, wie es AG1965_2 gezeigt hat oder
Verwendet einen Cursor, d.h. man bildet das dynamische SELECT-Statement, konvertiert dieses in ein ausführbares SELECT-Statement (PREPARE). Das konvertierte SELECT-Statement wird dann in das DECLARE-Statement eingebunden und danach folgt der übliche Verlauf, d.h. der Cursor muss geöffnet werden (OPEN), der einzelne/erste Datensatz gelesen werden (FETCH) und dann muss der Cursor wieder geschlossen werden (CLOSE).
Weder SET noch SELECT ... INTO können in Verbindung mit dynamischem verwendet werden.
Die Frage ist nur, warum sollte man an dieser Stelle 5 SQL-Statements ausführen, wenn man stattdessen mit 2 Statements auskommen kann?
Nein, ich habe mich nicht verzählt, das SQL-Statement kann auch direkt im PREPARE zusammengesetzt werden!
Birgitta
... das ist einfach zu beantworten:
values into ist kein SQL Standard, zudem ist die standard Version mit cursor im Fehlerfall einfacher zu behandeln - sprich defensiver. Das ist Dir aber vermutlich egal, Du empfiehlst ja auch naming *sys, commit(*none) und Datenschrank Verarbeitung nach LIBL - ich empfehle halt was anderes, lass doch jeden selbst entscheiden.
D*B
andreaspr@aon.at
11-11-18, 07:43
Das ist Dir aber vermutlich egal, Du empfiehlst ja auch naming *sys, commit(*none) und Datenschrank Verarbeitung nach LIBL - ich empfehle halt was anderes, lass doch jeden selbst entscheiden.
Ist ja wieder einmal amüsant zu lesen.
Birgittas Empfehlungen basieren so gut wie immer auf den jeweiligen Anforderungen.
Und ja, wenn ein Unternehmen noch niergends Commit im Einsatz hat, dann empfehle ich nicht bei einer kleinen Anpassung dies gleich zu verwenden. Da gehört vorher ein überlegtes Design her (auch fürs Testen).
Genauso könnte man behaupten, dass Dieter empfiehlt alles bestehende weg zu schmeißen und neu zu entwickeln und das am besten mit einer "richtigen" DB und einer "richtigen" Programmiersprache.
... set, values into und select into ohne commit sind klassische Kunstfehler. Gerade wenn man commit umgehen will, geht ohne cursor nur dirty read...
D*B
Nun, die Ausgangssituation beschränkte sich eben nicht auf die reine Set-Anweisung sondern auf die variable Bibliothek. Nun lassen sich eben Tabellen und Libnamen nicht per "?" angeben was wiederum zu dynamischem SQL führte.
Jedoch "das SQL-Statement kann auch direkt im PREPARE zusammengesetzt werden" stimmt zwar, aber ich prüfe das Ergebnis gerne in einer Variablen.
Und was die Anzahl der SQL's angeht so ist die letztlich egal (sind nur Speicherzugriffe), da eine VALUES-Anweisung implizit auch nichts anderes als Open/Fetch/Close machen kann.
Und ob nun commit oder nicht das soll wirklich jeder selber entscheiden.
Schließlich will man ja an Recoveryprozeduren auch noch verdienen;-).
Ansonsten vielen Dank an Birgitta die mit ihren Ausführungen die vorherigen Beiträge bestätigte.
Wenn ein SET-Statement in Verbindung mit einem SELECT-Statement ausgeführt wird, muss genau eine Zeile zurückkommen. Das war die Ausgangssituation!
Wenn man das Ganze dynamisch machen möchte bzw. muss (weil die Tabelle oder Bibliothek flexibel gehalten werden müssen), kann man entweder
ein VALUES ... INTO Statement dynamisch zusammensetzen und dann mit PREPARE und EXECUTE ausführen, wie es AG1965_2 gezeigt hat oder
Verwendet einen Cursor, d.h. man bildet das dynamische SELECT-Statement, konvertiert dieses in ein ausführbares SELECT-Statement (PREPARE). Das konvertierte SELECT-Statement wird dann in das DECLARE-Statement eingebunden und danach folgt der übliche Verlauf, d.h. der Cursor muss geöffnet werden (OPEN), der einzelne/erste Datensatz gelesen werden (FETCH) und dann muss der Cursor wieder geschlossen werden (CLOSE).
Weder SET noch SELECT ... INTO können in Verbindung mit dynamischem verwendet werden.
Die Frage ist nur, warum sollte man an dieser Stelle 5 SQL-Statements ausführen, wenn man stattdessen mit 2 Statements auskommen kann?
Nein, ich habe mich nicht verzählt, das SQL-Statement kann auch direkt im PREPARE zusammengesetzt werden!
Birgitta
Hallo,
hätte eine Frage dazu:
Ich bekomme bei folgenden Statement SqlCde=-305 SqlStt=22002(Anzeigervariable erforderlich) zurück.
In der Datenbank gibt es keinen Satz dazu.
VALUES(SELECT P_NAME FROM PERSONP
WHERE P_PENR = 58392 ) INTO ?
Wie müsste mein Statement aussehen das ich den Fehler abfange?
Danke
Tarki
Wenn eine Indikator-Variable verlangt wird bedeutet das, dass ein NULL-Wert zurückgegeben wird. Indikator Variablen werden mit Int(5) definiert und beim Execute unmittelbar nach der Ausgabe-Variablen nur durch ein Komma getrennt angegeben.
Sofern ein NULL-Wert ausgegeben wird, wird die Indikator-Variable mit -1 ausgegeben, was dann im Anschluss geprüft werden kann.
Birgitta
... das ist einfach zu beantworten:
values into ist kein SQL Standard, zudem ist die standard Version mit cursor im Fehlerfall einfacher zu behandeln - sprich defensiver. Das ist Dir aber vermutlich egal, Du empfiehlst ja auch naming *sys, commit(*none) und Datenschrank Verarbeitung nach LIBL - ich empfehle halt was anderes, lass doch jeden selbst entscheiden.
D*B
Dieter,
Ich hab' langsam die Schnautze voll!
Was sollen diese ständigen Angriffe!
Jedes Mal wenn ich etwas schreibe, versuchst Du mir mit unqualifizierten und unwahren Behauptungen an den Karren zu fahren.
Ich gehe von der Ausgangssituation aus und die ist hier nun mal so, dass viele weder unter Commit fahren und außerdem Ihre Daten in unterschiedlichen Bibliotheken hinterlegt haben.
SELECT ... INTO und VALUES ... INTO generieren beide im Untergrund einen Cursor, Öffnen diesen, Lesen den ersten Satz und schließen den Cursor wieder. Warum also 5 Statements schreiben, wenn es auch 2 tun. Im Fehlerfall wird jeweils ein SQLCODE (oh' Verzeihung ist ja nicht Standard!!!) und ein SQLSTATE ausgegeben, die abgeprüft werden können.
Desweiteren bin ich mit Sicherheit die letzte, die COMMIT *NONE empfiehlt. Gerade Journaling und Commitment-Control ist eines der Themen, die ich grundsätzlich empfehle!
Was die Namenskonventionen angeht, so überlasse ich das jedem selber. NUR sollte man wissen welche Konsequenzen dahinter stecken, wenn man statt System- SQL-Naming verwendet. Das erkläre ich auch immer und das ist weit mehr als das Trennkennzeichen zwischen Schema und Objekt (wobei beim System-Naming inzwischen auch der Punkt als Trennzeichen verwendet werden kann).
Ich denke das war jetzt wohl endgültig das letze Mal, das ich in diesem Forum irgendetwas gepostet habe.
Birgitta