Anmelden

View Full Version : Embedded SQL Kommando



Seiten : [1] 2

woki
15-12-04, 16:23
Hallo,
Ich führe in einem PGM ein Embedded SQL Statement (ich arbeite mit eienm Cursor) aus,
das mir leider kein Ergebnis zurückliefert.



SqlStm = 'SELECT PROGPW, AUSFPW, IDNRPL, ANGBPL,
PNAMPW, HOLZPW, KZ05PW, KZ06PW, AUSNPW, AUSDPW, DTNEPW
From RBPFILE/PRGSTP
Inner Join PRGLEP On PROGPW = PROGPL
And AUSFPW = AUSFPL
Where STATPW = ''A''
Order by PROGPW, AUSFPW, IDNRPL, ANGBPL
For read only'


Hier möchte ich gerne dynamische Selektierungen einbauen:



DPROG S 100 Inz(' and PROGPW = :PROGD0')
DAUSF S 100 Inz(' and AUSFPW = :AUSFD0')
DIDNR S 100 Inz(' and IDNRPL = :IDNRD0')
DANGB S 100 Inz(' and ANGBPL = :ANGBD0')


if PROGD0 <> ' '
eval cmd = %trim(cmd) + PROG
endif
if AUSFD0 <> ' '
eval cmd = %trim(cmd) + AUSF
endif
if IDNRD0 <> 0
eval cmd = %trim(cmd) + IDNR
endif
if ANGBD0 <> ' '
eval cmd = %trim(cmd) + ANGB
endif


Das SqlStm habe ich entsprechend geändert:



...
Where STATPW = ''A'' '
+ ':cmd' +
'Order by
...


Es klappt ohne den cmd-Teil, aber warum nicht mit?
Kann mir jemand helfen?

Fuerchau
15-12-04, 19:02
Bei embedded SQL können Parameter (:FELD) nicht als Variablen eingesetzt werden, da Parameter bereits durch den Precompiler in Felder aufgelöst werden (Umwandlungsliste).
Wenn du dynamische SQL's zusammenbauen willst, musst du den gesamten Select in einer Variablen zusammenbauen und per "Prepare Statement" vorbereiten.
Anschließend kannst du per Execute das Statement ausführen und den Cursor öffnen.

Versuche doch alternativ die Where-Bedingung besser vorzubereiten:

where ... and (:PROGD0 = ' ' or PROGPW = :PROGD0) ...

woki
16-12-04, 07:51
Ich habe den Fehler gefunden, so klappts:



if PROGD0 <> ' '
eval cmd = %trim(cmd) + PROG + '''' + PROGD0 +''''
endif
if AUSFD0 <> ' '
eval cmd = %trim(cmd) + AUSF + '''' + AUSFD0 +''''
endif
if IDNRD0 <> 0
eval cmd = %trim(cmd) + IDNR + %char(IDNRD0)
endif
if ANGBD0 <> ' '
eval cmd = %trim(cmd) + ANGB + '''' + ANGBD0 +''''
endif

eval SqlStm =
....
'Where STATPW = ''A'' ' +
cmd +
' Order by PROGPW, AUSFPW,.....

B.Hauser
16-12-04, 08:11
Hi,

du kannst in deinem Select-Statement Parameter-Marker (?) an Stelle der Variablen verwenden.

In deinem Open-Statement gibts Du die entsprechenden Host-Variablen in der Reihenfolge an, wie sie im Select-Statement verwendet werden.

Beispiel:


Stmt = 'Select Feld1 +
from MyFile +
where MyFeld1 = ''?'' +
and MyFeld2 = ?';

C/EXEC SQL Open MyCsr Using :MyVar1, :MyVar2
C/END-EXEC


Dies ist vorallem dann sinnvoll, wenn das gleiche Select-Statement mehrfach mit unterschiedlichen Variablen ausgeführt werden muss.

Die Konvertierung des Strings in ein ausführbares SQL-Statement und das DECLARE-Statement müssen dann nicht erneut ausgeführt zu werden.

Es muss nur der Cursor geschlossen und wieder neu eröffnet werden.

Birgitta

woki
16-12-04, 14:52
Mein Problem ist es, eine Art Filter zu Programmieren.
Das passiert in einem SQLRPGLE-Programm. Die Daten werden an ein VARPG-Programm weitergegeben und dort in einer Subfile abgefragt.
Im VARPG-Programm gibt es 4 Eingabefelder, nach denen man die große Datenmenge selektieren kann: PROGD9, AUSFD9, ANGBD9 und IDNRD9.
Deswegen können die obigen Felder gefüllt sein oder auch nicht. Um das Abzufragen baue ich mir die cmd-Variable so zusammen:


DPROG S 100 Inz(' and PROGPW = ')
DAUSF S 100 Inz(' and AUSFPW = ')
DIDNR S 100 Inz(' and IDNRPL = ')
DANGB S 100 Inz(' and ANGBPL = ')

C if PROGD0 <> ' '
C eval cmd = %trim(cmd) + PROG + '''' + PROGD0 + ''''
C endif
C if AUSFD0 <> ' '
C eval cmd = %trim(cmd) + AUSF + '''' + AUSFD0 + ''''
C endif
C if IDNRD0 <> 0
C eval cmd = %trim(cmd) + IDNR + %char(IDNRD0)
C endif
C if ANGBD0 <> ' '
C eval cmd = %trim(cmd) + ANGB + '''' + ANGBD0 + ''''
C endif

Oder weiß einer eine andere Lösung hierfür?

Fuerchau
16-12-04, 15:05
Naja, ganz so dynamisch ist es nicht nötig:

/exec sql
c+ declare mycursor for cursor as
c+ SELECT PROGPW, AUSFPW, IDNRPL, ANGBPL,
c+ PNAMPW, HOLZPW, KZ05PW, KZ06PW, AUSNPW, AUSDPW, DTNEPW
c+ From RBPFILE/PRGSTP
c+ Inner Join PRGLEP On PROGPW = PROGPL
c+ And AUSFPW = AUSFPL
c+ Where STATPW = 'A'
c+ and (:PROGD0 = ' ' or PROGPW = :PROGD0)
c+ and (:AUSFD0 = ' ' or AUSFPW = :AUSFD0 )
c+ and (:IDNRD0= ' ' or IDNRPL = :IDNRD0)
c+ and (:ANGBD0 = ' ' or ANGBPL = :ANGBD0 )
c+ Order by PROGPW, AUSFPW, IDNRPL, ANGBPL
c+ For read only'
c/end-exec

c/exec sql
c+ open mycursor
c/end-exec

Da ja nur deine Where-Klausel variabel ist, geht das so viel einfacher.

B.Hauser
16-12-04, 15:05
Hallo,

verwende doch einfach statisches SQL!

Beispiel:


C/EXEC SQL
C+ DECLARE MyCursor CURSOR FOR
C+ SELECT Feld1, Feld2, Feld3, FeldN
C+ FROM MyFile
C+ WHERE FIRNR = :HstFINR
C+ AND MyLAND BETWEEN :VonLAND AND :BisLAND
C+ AND MyPLZ BETWEEN :VonPLZ AND :BisPLZ
C+ AND MyORT BETWEEN :VonORT AND :BisOrt
C+ AND MyKND BETWEEN :VonKND and BisKND
C* ... und so weiter
C+ ORDER BY MyLAND, MyPLZ, MYBNR
C+ For Read Only
C/END-Exec


Je nach dem, ob ein Wert eingegeben wurde oder nicht, werden die VON/BIS-Angaben entweder mit dem eingegebenen Wert oder mit *LoVal/HiVal gefüllt.

Der Query-Optimizer kann solche Abfragen korrekt auflösen.

Birgitta

woki
16-12-04, 16:14
Super, vielen Dank, ich habe diesen Teil eingebaut:

c+ and (:PROGD0 = ' ' or PROGPW = :PROGD0)
c+ and (:AUSFD0 = ' ' or AUSFPW = :AUSFD0)
c+ and (:IDNRD0= ' ' or IDNRPL = :IDNRD0)
c+ and (:ANGBD0 = ' ' or ANGBPL = :ANGBD0)


Allerdings habe ich noch ein Problem:
Ich arbeite mit einem SQLRPGLE- und einem VARPG-Programm.
Das Varpg steuert und zeigt die Daten in einer Subfile an, das SQLRPGLE-Programm ermittelt die Daten.
Hier arbeite ich mit einem 20.000stelligen Datenpuffer, der die relevanten Daten von einem in das andere Programm übergibt. Da große Datenmengen nicht in den Puffer passen, muß ich die Subfile von VARPG-Seite nachladen. Das obige Programm ermittelt die Daten beim ersten Aufruf. Für alle weiteren muß ich eine andere SQL-Abfrage erstellen mit verschachtelten where-Klauseln.

Beispiel 1:
ANGBD9, IDNRD9 und AUSFD9 sind gefüllt

C+ Where STATPW = 'A'
C+ and ANGBPL = :ANGBD9
C+ and IDNRPL = :IDNRD9
C+ and AUSFPW = :AUSFD9
C+ and PROGPW > :PROGD9

Beispiel 2:
nachladen - PROGD9 & AUSFD9 ist gefüllt.
D9-Felder sind die Felder des letzten Datensatzes, die nächsten müssen ermittelt werden.


C+ Where STATPW = 'A'
C+ and ANGBPL > :ANGBD9
C+ and IDNRPL >= :IDNRD9
C+ and AUSFPW = :AUSFD9
C+ and PROGPW = :PROGD9
C+ or (STATPW = 'A'
C+ and IDNRPL > :IDNRD9
C+ and AUSFPW = :AUSFD9
C+ and PROGPW = :PROGD9)


Beipiel 3:
nachladen - PROGD9 ist gefüllt.


C+ Where STATPW = 'A'
C+ and ANGBPL > :ANGBD9
C+ and IDNRPL >= :IDNRD9
C+ and AUSFPW >= :AUSFD9
C+ and PROGPW >= :PROGD9
C+ or (STATPW = 'A'
C+ and IDNRPL > :IDNRD9
C+ and AUSFPW >= :AUSFD9
C+ and PROGPW >= :PROGD9)
C+ or (STATPW = 'A'
C+ and AUSFPW > :AUSFD9
C+ and PROGPW >= :PROGD9)
C+ or (STATPW = 'A'
C+ and PROGPW > :PROGD9)

Da ich 4 Felder zur Selektion habe müßte ich dann 16 (!!!) einzelne Where-Bedingungen schreiben.
Hat dafür vielleicht jemand eine Lösung?

mk
16-12-04, 16:28
Hallo Woki,

warum machst Du Dir das mit dem Datenpuffer so schwierig ?

Erstelle beim Aufruf deines Programms eine DTAQ.
( Achtung Namensvergabe muss eindeutig sein wenn mehrere
VRPG Clients die Anwendung starten).

Dein AS 400 Programm füllt die Werte in die DTAQ.
Wenn dein AS 400 Programm fertig ist
liest dein VARPG die DTAQ und schreibt die Subfile.

Hört sich schwierig an ist aber ganz einfach.

Ausserdem kann man sich das lästige Nachladen sparen.

Gruss Michael

Fuerchau
16-12-04, 16:42
Kann VARPG kein embedded SQL ?
Ganz schön kompliziert :( für eine einfache Anzeige !