PDA

View Full Version : SQLRPG - Die ??.



malzusrex
22-05-07, 14:29
Moin *all!

Irgendwie stehe ich heute mal wieder auf den Schlauch, und ich benötige Eure Hilfe. Ich möchte per SQl einen Wert ermitteln. Das SQL-Stmt. habe ich interactive getestet und liefert einen Wert.


d Jahr s 2s 0
d qa s 2s 0
d Anzahl s 3u 0
d
d SQL_stmt s 512

c
c Eval SQL_stmt = 'Select Count(Distinct(rswoc)) '+
c 'from grresp where rsjah = ' +
c ':jahr and rsqua = :qa'
c
* Declare Cusor
c/exec sql
c+ Declare Cursor1 Cursor For SQLstmt
c/end-exec
* Setzen Sprachen ID
c/exec sql
c+ Set Option SrtSeq = *LangIdShr
c/end-exec
* Setzen Modus für Close SQL-Cursor
c/exec sql
c+ Set Option CloSqlCsr = *EndMod
c/end-exec
c eval jahr = 07
c eval qa = 02
* Prepare Cursor
c/exec sql
c+ Prepare SQLstmt From :SQL_stmt
c/end-exec
c/exec sql
c+ Fetch Cursor1 InTo :anzahl
c/end-exec
c
c Eval *inlr = *On


Nur bei diesem kleine SQLRPG ist mein Feld ANZAHL immer 0.
Wo liegt denn nun hier mein Fehler ?

Gruß Ronald

Fuerchau
22-05-07, 15:53
Hostvariablen funktionieren nicht mit Prepare !
Du must den Inhalt der Variablen in den SQL-String einbauen und dann preparen.

B.Hauser
22-05-07, 18:56
Hallo,

hier zunächst einige Anmerkungen:
1. Hast Du das Open-Statement nur beim Kopieren vergessen oder fehlt es überhaupt?

2. Wenn Du bereits auf Release V5R4 wärst, könntest Du Dein Programm nicht kompilieren. Ab Release V5R4 muss das Set Option Statement im Source Code VOR allen anderen SQL-Statements stehen und nur ein einzige SET OPTION Statement darf angegeben werden. Beides wird in Release V5R4 abgeprüft und führt zu Compile Fehlern. Wenn Du im SET OPTION Statement mehrere Optionen angeben willst, muss Du die einzelnen Optionen nur durch Kommata trennen:


C/EXEC SQL Set Option Commit = *NONE, LangIdShr = *Hex
C/END-EXEC


3. Die Option CLOSQLCSR = *ENDMOD ist ein Performance-Killer, zumindest dann, wenn mit statischem SQL gearbeitet wird und das Modul mehrfach aufgerufen wird. Der Grund hierfür liegt darin, dass die ODPs (Offene Datenpfade) jeweils bei Modul-Ende gelöscht werden. Bei den folgenden Aufrufen muss jeweils die komplette Optimierung oder Full Open erfolgen (z.B. Aktivierungs-Plan erstellen oder Validieren, Indices prüfen, temporäre Objekte erstellen und mit Daten füllen), alles in allem der zeitaufwändigste Prozess bei der Ausführung eines SQL-Statements. Steht CLOSQLCSR auf *ENDACTGRP können einmal geöffnete Datenpfade wiederverwendet werden, d.h. es erfolgt nur ein Pseudo-Open, sprich lediglich die Daten in den temporären Objekten werden aktualisiert.

Wenn Du sicher sein möchtest, dass Dein Cursor auch wirklich geschlossen war, mach einfach ein CLOSE unmittelbar vor dem Open-Statement (bei Statischem SQL oder dynamischem SQL mit Parameter-Markern s.u.) oder dem Prepare-Statement (bei dynamischem SQL)

5. Wenn Du nur genau dieses Statement ausführen willst, macht dynamisches SQL keinen Sinn. Bei Dynamischem SQL muss zur Laufzeit ein Syntax Check ausgeführt werden und der String in ein ausführbares SQL-Statement konvertiert werden, bevor die eigentliche Optimierung stattfindet.

6. Anstatt die Variablen zu Fuß in den String hinein zu priemeln kannst Du mit Parameter-Markern arbeiten. An der Stelle, an der Deine Variablen stehen sollen setzt Du einfach eine Fragezeichen (Parameter-Marker) in Deinem String. Die eigentlichen Variablen werden dann bei dem Open-Statement über Using angegeben.


C/EXEC SQL Open MyCsr Using :HostVar1, :HostVar2, ...
C/END-EXEC


Wenn Du mit Parameter-Markern arbeitest und das gleiche Statement mit unterschiedlichen Host-Variablen-Werten ausführen willst, brauchst Du das Prepare-Statement nicht mehr erneut ausführen.

7. Du solltes nach jedem SQL-Statement entweder den SQLCOD (SQLCODE) oder den SQLSTT (SQLSTATE) beides Felder aus der SQLCA (SQL Communication Area), die vom Precompiler eingebunden wird und mit jedem ausgeführten SQL-Statement aktualisiert wird.

Birgitta

malzusrex
23-05-07, 13:54
So, danke euch beiden.
ich habe jetzt mal Eure Infos eingepflegt, und bin zu folgenden Funktionierenden Proggi gekommen:


d jahr s 2s 0
d qa s 2s 0
d anzahl s 2s 0

c
c/exec sql Set Option SrtSeq = *LangIdShr
c/end-exec
c/exec sql Declare Cursor1 Cursor For
c+ Select Count(Distinct(rswoc)) as anzahl
c+ from grresp
c+ where rsjah = :jahr
c+ and rsqua = :qa
c/end-exec
c/exec sql Close Cursor1
c/end-exec
c eval jahr = 07
c eval qa = 02
c/exec sql Open Cursor1 Using :jahr, :qa
c/end-exec
c/exec sql Fetch Cursor1 Into :anzahl
c/end-exec
c
c Eval *inlr = *On


mir ist auch klar, das ich damit nicht den schönheitspreis gewinnen werde.

@Birgitta
Option CLOSQLCSR = *ENDMOD
hatte ich eingebaut, da ich in einem Programm folgendes Problem hatte:
Dynamisches SQL mit "Select * from kunden where name like 'K%'
bei dem 2. Aufruf mit "Select * from kunden where name like 'S%' hatte ich dann keine Daten, weil er nur noch die Kunden mit "K" im Zugriff hatte. Darum habe ich halt die OPTION eingebaut.

Gruß Ronald

Fuerchau
23-05-07, 16:19
In deinem Programm steht der Close noch an falscher Stelle (mit ODP's) hat das noch nichts zu tun.

Wenn ein Select nur 1 Zeile als Ergebnis hat (bei count sehr wahrscheinlich) kannst du das noch abkürzen:

Select Count(Distinct(rswoc)) into :anzahl
c+ from grresp
c+ where rsjah = :jahr
c+ and rsqua = :qa

Übrigens:
Das "USING" beim Open wird ignoriert, da du beim Declare keine Parameter sonder Hostvariablen deklariert hast.
Das Using kannst du dir dann schenken.

Using ist dann erforderlich, wenn man sog. Parametermarker verwendet:

"select ... where rsjah = ? and rsqua = ?".
Diesen dann preparen und dann mit "open ... using ..." öffnen.

malzusrex
23-05-07, 17:04
Danke,

habe es jetzt noch eingekürzt.
Das mit den Parametern habe ich dann glaube ich auch gefressen. Mache ich in Delphi mit durchgriff zur AS/400 ja eigentlich auch so in ähnlicher Form.

Gruß Ronald

B.Hauser
23-05-07, 19:14
Hallo,


In deinem Programm steht der Close noch an falscher Stelle (mit ODP's) hat das noch nichts zu tun.

Das Problem bei OPEN und CLOSE ist, dass ein Cursor nicht erneut geöffnet werden kann, wenn er bereits geöffnet ist. Da ein CLOSE eventuell auch mal vergessen wird, ist es am sichersten den Cursor unmittelbar vor dem OPEN (nochmals) zu schließen. War der Cursor zu dem Zeitpunkt geöffnet, wird er geschlossen, war er nicht geöffnet umso besser.

Bei einem Soft- oder Pseudo-Close (also einem Close im embedded SQL oder in einer SQL-Stored Procedure oder User Defined Function) wird kein wiederverwendbarer ODP gelöscht. Ein Pseudo-Close bewirkt lediglich, dass die Daten in den temporären Objekten des ODP beim nächsten Open aktualisiert werden. Über die Compile-Option CLOSQLCSR wird definiert wann ein Hard Close erfolgen soll, also entweder beim Ende der Aktivierungsgruppe oder beim Ende eines Moduls. Je nachdem wie diese Option eingestellt ist, wird der ODP entweder beim Ende des Moduls oder beim Beenden einer Aktivierungsgruppe komplett gelöscht. Im Klartext heißt das, dass bei einem erneuten Aufruf die komplette Optimierung (Full Open) mit allen Konsequenzen erneut ausgeführt werden muss.

@Ronald:
Ich würde das ganze Programm noch wie folgt kürzen:


d jahr s 2s 0
d qa s 2s 0
d anzahl s 2s 0

c
c/exec sql Set Option SrtSeq = *LangIdShr
c/end-exec
C Clear Anzahl
c eval jahr = 07
c eval qa = 02
C/Exec SQL
c+ Select Count(Distinct(rswoc))
C+ Into :Anzahl
c+ from grresp
c+ where rsjah = :jahr
c+ and rsqua = :qa
c/end-exec

c Eval *inlr = *On


Birgitta