View Full Version : SQLRPG
Wer kann mir einen hilfreichen Tipp geben ??
Situation : Ich baue in einem RPG IV Programm anhand verschiedener Bedingungen ein SQL-Statement in einer Charakter-Variablen über den CAT-Befehl zusammen. Wie kann ich dieses SQL-Statement aus dem RPG-Programm heraus ausführen lassen ??
Vielen Dank für Eure Hilfe.
Ursus
Hallo Ursus,
hier ein Beispiel für dynamisches SQL mit Cursor:
$SCLCMD ist der zusammengesetzte Befehl (Select .....)
Sql-Command aufbereiten
C/EXEC SQL
C+ Prepare SQLBP From :$SQCMD
C/END-EXEC
*
* Cursor Definieren
C/EXEC SQL
C+ Declare $SQLC1 Cursor For SQLBP
C/END-EXEC
*
* Cursor öffnen
*----------------------*
C/EXEC SQL
C+ Open $SQLC1
C/END-EXEC
*
* Verarbeiten SQL-Command in Schleife
*--------------------------------------*
C Do *Hival
*
C/EXEC SQL
C+ Fetch $SQLC1
C+ INTO :$SQLAB, :$SQZZ, :$SQXX, :$SQYY
C/END-EXEC
*
* Ende-Bedingungen
C IF SQLCOD = 100
C leave
C endif
*
* Nächster Satz (Fehler)
C if SQLCOD < 0
C iter
C endif
*
* Verarbeitung
* Was auch immer
C enddo
*
* Schliessen Cursor
*-------------------*
C/EXEC SQL
C+ Close $SQLC1
C/END-EXEC
Hallo Frau Hauser,
vielen Dank für Ihre Antwort, ich habe Ihre Idee in mein Programm wie folgt in mein Programm eingebaut :
**
D SQLSTRG S 512A
**
** In SQLSTRG steht zum Ze***unkt der
** Ausführung folgendes Statemnet :
** SELECT COUNT(*) INTO :#ANZ FROM biliothek/
** dateiname WHERE bedingungen
**
C/EXEC SQL
C+ PREPARE SQLBP FROM :SQLSTRG
C/END SQL
**
C/EXEC SQL
C+ DECLARE C1 CURSOR FOR SQLBP
C/END-EXEC
**
C/EXEC SQL
C+ OPEN C1
C/END-EXEC
**
C/EXEC SQL
C+ FETCH C1
C/END-EXEC
C EVAL O8ANZ = #ANZ
**
Nach der Ausführung des Prepare Statements kommt es zu dem Fehler :
SQL0312 CQLCODE -312 "Host Variable nicht definiert oder nicht benutzbar"
Ist meine Variable zu lang, oder habe ich sie falsch definiert ??
Vielen Dank für Ihre Mühe,
Marc
[Dieser Beitrag wurde von Ursus am 09. August 2001 editiert.]
Bei einer Prepared-Select-Anweisung kann kein INTO verwendet werden !!!!
Bei der Fehlermeldung ist die Variable #ANZ gemeint. Diese kann nur der RPG-Kompiler kennen und nicht der SQL-Analyser, der das Prepare durchführt. Schließlich wird die Variable #ANZ vom RPG-Compiler bereits in eine Adressse umgesetzt, so dass die Variable so nicht mehr bekannt ist.
Nehmen Sie das obige Beispiel also wörtlich, definieren Sie den Select OHNE INTO und verwenden Sie anschließend OPEN, FETCH ... :INTO und CLOSE.
Hallo
Das Beispiel für das Dynamische SQL stammt aus einem Programm, das in dieser Form im Einsatz ist. Fetch-Anweisungen mit INTO sind durchaus möglich!
Allerdings war die Länge des Commands unter RPGIII auf 256 Stellen begrenzt! Unter RPGIV habe ich noch kein dynamisches SQL verwendet, bei dem der Command länger als 256 Stellen war
Vermutlich besteht diese Grenze noch
Vielen Dank für Ihre Tipps !
Ich habe jetzt nur noch ein Problem :
Wird der komplette String als "einzeiliges SQL-Statement" verarbeitet oder wird wie im Debugger angezeigt, ein Zeilenumbruch nach 60 Zeichen vorgenommen ??
Die Abfrage läuft, wenn das SQL-Statement maximal 60 Zeichen enthält, wenn ich mehr als 60 Zeichen verwenden will, bekomme ich bei dem PREPARE-Statement die Fehlermeldung SQLCODE -206 (Spalte nicht in angegebener Tabelle definiert) obwohl das gleiche Statement im interaktiven SQL läuft.
Muß ich irgendwelche Trennzeichen beachten oder wo liegt jetzt der Fehler ??
Vielen Dank, Marc
Hallo Marc,
ich habe gestern Mittag den Select-Befehl nicht genau gelesen.
Bei dem angegebenen SELECT-Befehl handelt es sich um eine Verarbeitung ohne Cursor.
Diese Verarbeitung ist möglich, wenn genau ein Ergebnis-Satz erwartet wird. Die INTO-Angabe erfolgt in der SELECT-Anweisung.
In diesem Fall darf nur FETCH angegeben werden.
Werden mehrere Sätze, die einzeln verarbeitet werden sollen erwartet, darf die INTO-Anweisung nicht im SELECT erfolgen. Die Verarbeitung erfolgt in einer DO-Schleife bei der die einzelnen Sätze durch FETCH INTO verarbeitet werden.
Diese Art der Verarbeitung funktionniert natürlich auch, wenn nur ein Ergebnis-Satz erwartet wird.
Was die Länge des Strings angeht, habe ich bis zu 256-Zeichen noch nie Probleme gehabt.
Wie wurde der String aufgebaut? Vielleicht liegt der Fehler dort
B. Hauser
Hallo Birgitta,
ich habe auf folgende Weise das SQL-Statement aufgebaut :
D #SQLCMD S 1024A
D CSQL 'SELECT COUNT(*) FROM SWDAT-
D /MDBF00 WHERE BFFIRM = ''000'''
D ASQLCMD S 1 DIM(1024)
MOVEA CSQL ASQLCMD(1)
IF I1PROG <> *BLANKS
EVAL #SQL2 = ' AND BFPROG = I1PROG'
MOVEA #SQL2 ASQLCMD(56)
ENDIF
IF I1SAB <> '*'
EVAL #SQL2 = 'AND BFSAB = I1SAB'
MOVEA #SQL2 ASQLCMD(75)
ENDIF
MOVEA ASQLCMD #SQLCMD
C/EXEC SQL
C+ PREPARE SQLBP FROM :#SQLCMD
C/END-EXEC
Im Debugger sieht das Statement vor dem Prepare folgendermaßen aus :
....5...10...15...20...25...30...35...40...45...50 ...55...60
'SELECT COUNT(*) FROM SWDAT/MDBF00 WHERE BFFIRM = '000' '
'AND BFPROG = I1PROG'
Zuerst habe ich das Statement über den CAT-Befehl zusammengebaut, als dabei Fehlermeldungen kamen, habe ich eine Datenstruktur erstellt und diese wie oben beschrieben gefüllt. Beide Wege funktionieren, wenn ich nur maximal 60 Stellen fülle, bei mehr als 60 Stellen ergeben beide Wege die beschriebene Fehlermeldung.
Ich habe die Variablen auch schon auf 100 gekürzt um zu testen, ob es dann fehelrfrei läuft, aber auch das bringt die gleiche Fehlermeldung.
Was habe ich falsch gemacht ? Was habe ich noch für Möglichkeiten ?
Hallo Birgitta,
ich habe auf folgende Weise das SQL-Statement aufgebaut :
D #SQLCMD S 1024A
D CSQL 'SELECT COUNT(*) FROM SWDAT-
D /MDBF00 WHERE BFFIRM = ''000'''
D ASQLCMD S 1 DIM(1024)
MOVEA CSQL ASQLCMD(1)
IF I1PROG <> *BLANKS
EVAL #SQL2 = ' AND BFPROG = I1PROG'
MOVEA #SQL2 ASQLCMD(56)
ENDIF
IF I1SAB <> '*'
EVAL #SQL2 = 'AND BFSAB = I1SAB'
MOVEA #SQL2 ASQLCMD(75)
ENDIF
MOVEA ASQLCMD #SQLCMD
C/EXEC SQL
C+ PREPARE SQLBP FROM :#SQLCMD
C/END-EXEC
Im Debugger sieht das Statement vor dem Prepare folgendermaßen aus :
....5...10...15...20...25...30...35...40...45...50 ...55...60
'SELECT COUNT(*) FROM SWDAT/MDBF00 WHERE BFFIRM = '000' '
'AND BFPROG = I1PROG'
Zuerst habe ich das Statement über den CAT-Befehl zusammengebaut, als dabei Fehlermeldungen kamen, habe ich eine Datenstruktur erstellt und diese wie oben beschrieben gefüllt. Beide Wege funktionieren, wenn ich nur maximal 60 Stellen fülle, bei mehr als 60 Stellen ergeben beide Wege die beschriebene Fehlermeldung.
Ich habe die Variablen auch schon auf 100 gekürzt um zu testen, ob es dann fehelrfrei läuft, aber auch das bringt die gleiche Fehlermeldung.
Was habe ich falsch gemacht ? Was habe ich noch für Möglichkeiten ?
SQL Sucht die variablen I1PROG und I1SAB in der Datei !
Sie möchten aber den Inhalt !
LÖsung:
D BED1 100A INZ
D BED2 100A INZ
IF I1PROG <> *BLANKS
EVAL BED1 = ' AND BFPROG = '''' + I1PROG + ''''
ENDIF
IF I1SAB <> '*'
EVAL BED2 = ' AND BFSAB = '''' + I1SAB + ''''
ENDIF
EVAL #SQLCMD = 'SELECT COUNT(*) ... ' + BED1 + BED2
ACHTUNG:
Beachten Sie dass die Prepareanweisung nur 1 Mal funktioniert solange das Programm aktiv bleibt. Das SQL-Statement SQLBP wird erst nach Trennung der Verbindung zur Datenbank wieder gelöscht.
Ihre Lösung ist daher nicht performant !
Definieren Sie lieber die benötigten Varianten für ihren SELECT direkt und führen die entsprechende Anweisung zur Laufzeit aus.
Vorteil: Das Prepare erfolgt bereits zur Compile-Zeit !
select
when I1PROG = *BLANK and I1SAB=*BLANK
/EXEC-SQL
+SELECT ... (Variante 1)
/END-EXEC
when I1PROG <>*BLANK and I1SAB=*BLANK
/EXEC-SQL
+SELECT ... WHERE BFPROG=:I1PROG (Variante 2)
/END-EXEC
when ...
:
:
endsl
Die Bibliothek muss auch nicht angegeben werden, da diese über die Librarylist automatisch ermittelt wird.