PDA

View Full Version : SQLRPG



Seiten : [1] 2

Ursus
08-08-01, 14:57
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

B.Hauser
09-08-01, 07:23
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

Ursus
09-08-01, 08:07
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.]

Fuerchau
09-08-01, 10:40
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.

B.Hauser
09-08-01, 12:23
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

Ursus
09-08-01, 12:54
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

B.Hauser
10-08-01, 07:34
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

Ursus
10-08-01, 08:36
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 ?

Ursus
10-08-01, 08:41
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 ?

Fuerchau
10-08-01, 09:34
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.