PDA

View Full Version : Statisches Embedded SQL: Verarbeitung eines Arrays möglich?



Seiten : [1] 2

dschroeder
24-05-23, 14:13
Hallo zusammen,
ich glaube nicht, dass es geht. Aber ich frage trotzdem mal nach:

Nehmen wir mal an, ich hätte 10 Kundennummern in einem Array. Kann ich ein statisches SQL schreiben, in dem diese 10 Kundennummern des Arrays verarbeitet werden?

Wenn die Kundennummern in einer Datenbanktabelle ständen, wäre der Zugriff mit SQL ja kein Problem (über Join).

Wenn die Kundennummern in einem JSON-Dokument ständen, könnte ich mit der JSON_TABLE Funktion auch ziemlich einfach per embedded SQL etwas damit machen.

Aber nur ein reines RPG-Array? Da ist wohl nichts zu machen, oder?

Dieter

Fuerchau
24-05-23, 22:19
Diese Frage verstehe ich nun so nicht.
Du kannst ein Array mit einem SQL füllen, in dem du beim Fetch das Array als Ziel angibst und die Anzahl Zeilen (Elemente) angibst. Somit wird mit einm SQL das Array befüllt.
Ebenso kannst du ein Array als Cursor zurückgeben, um somit das Array per "Insert .. Select from" in eine Tabelle schreiben kannst.
Wenn du das Array als Zoned-Felder definierst, kannst du diese in eine DS packen und die DS als Char oder sogar CLOB insgesamt lesen und schreiben. INT oder PACKED-Arrays kannst du in BINARY oder BLOBS verwenden, was allerdings alles nicht Typ-Sicher ist.
Oder du verwendest direkt die ARRAY-Funktion im SQL.
Nachzulsen in der SQL-Reference.

B.Hauser
25-05-23, 07:25
Mir ist nicht klar, an welcher Stelle du das Array einsetzen willst.

Allerdings ist es so, dass man im Statischen SQL eigentlich weder ein Array noch einzelne Elemente direkt angeben kann.
Wenn Du mit einer Datenstruktur arbeitest, die 10 Elemente einzeln definierst (und benennst) und dann mit dem Array überlagerst, kannst Du die Unterfelder (z.B. in den WHERE-Bedingungen) und/oder die Datenstruktur (beim Fetch) verwenden. Wenn Du mit IN() arbeiten willst, musst Du die Unterfelder einzeln auflisten.
Ansonsten sind für einen Multiple Row Fetch nur Array-Datenstrukturen zulässig.

dschroeder
25-05-23, 09:36
Vielen Dank für Eure Antworten.

Da habe ich mich wohl missverständlich ausgedrückt:
Ich möchte das Array nicht mit SQL füllen!
Ich habe ein gefülltes Array und möchte das per SQL abarbeiten!

Konkretes Beispiel:


In Programm A kann man beliebig viele Kunden selektieren.
Programm B soll für diese Kunden eine Auswertung erstellen.


Bisherige Idee zur Implementierung:
Programm A schreibt alle selektierten Kundennummern in eine (temporäre) Tabelle. Danach verarbeitet Programm B diese temporäre Tabelle und macht z.B. einen Join von Temporärer Tabelle zur echten Kundentabelle und erzeugt die Auswertung. Z.B. Eine Liste aller selektierten Kunden mit ihren Adressen.

Ich finde das Handling mit temporären Tabellen nicht sonderlich schön. Eigentlich würde es mir ja reichen, wenn Programm A die vom User angeklickten (also zu selektierenden) Kunden in ein Array schreibt (natürlich nicht die ganzen Kunden, sondern nur die Schlüssel, also die Kundennummer).
Dann könnte das Array an das Auswertungsprogramm übergeben werden. Das Auswertungsprogramm müsste dann das Array abarbeiten.
Meine Frage war, ob man so ein Array irgendwie mit SQL-Mitteln abgreifen kann. Wäre das Array ein JSON-Array, könnte man mit JSON_TABLE das Array wie eine Tabelle verwenden und z.B. beim Join benutzen.

Mir ist allerdings inzwischen eingefallen, dass ich bei Arrays noch ein weiteres Problem hätte: Wenn ich das Auswertungsprogramm im Hintergrund arbeiten lassen möchte, müsste ich das Array ja im SBMJOB übertragen. Das klappt ja auch nicht. Jedenfalls würde es nicht schön werden.

Deshalb werde ich wahrscheinlich die zu selektierenden Daten per Tabelle zwischen den Programmen austauschen.

RobertMack
25-05-23, 11:00
Auch wenn's nicht mehr zeitgemäß erscheint, beim CALL von A nach B darf ein PARM auch eine DS sein...

Fuerchau
25-05-23, 11:36
Das Handling mit temporären Tabellen hat sich generell vereinfacht.
Stichwort: Global Temporary Table (GTT)
Die GTT wird im Programm einfach per SQL definiert.
Programm A => Insert into GTT
Programm B => Select * from GTT

https://www.ibm.com/docs/en/i/7.3?topic=language-declaring-global-temporary-table

Die GTT ist eine Tabelle in der QTEMP die automatisch erstellt und wieder gelöscht wird.

Ein Array als Tabelle geht zwar auch, das ist jedoch veraltet.
Dafür musst du eine externe SQL-Prozedure mit "returns table ..." definieren.
Im ILERPG kannst du dann das Array laden und beim Verlassen einen "exec sql return table ...." ausführen.
Da sind GTT's erheblich einfacher.

B.Hauser
25-05-23, 14:02
Frage: Was würde denn an dieser Stelle gegen dynamisches SQL sprechen?

Den Inhalt des Arrays mit als String aufbereiten (z.B. mit der RPG Built-In-Function %CONCATARR).
Und dann das SQL Statement dynamisch aufbereiten und in den WHERE-Bedingungen bei einer IN-Anweisung den String einbinden (etwa so).


StingArr = %CONCATARR(', ': YourArr);

CmdSQL = 'SELECT ... +
FROM ... +
WHERE YourCol In (' concat :StringArr concat ')' +
...'
//Prepare
//Declare
//Open
//Fetch
//Close

dschroeder
25-05-23, 15:34
Nochmals vielen Dank für eure Antworten.

Ich habe ja keine Schwierigkeiten, das Problem an sich zu lösen. Mir sind auch diverse Möglichkeiten bewusst (u. a, dynamisches SQL).
Ich wollte einfach mal wissen, ob sich da irgendetwas getan hat und man Arrays vielleicht inzwischen sehr einfach mit statischem SQL verarbeiten kann.
Ich hatte mir schon gedacht, dass das nicht so einfach geht. Aber manchmal gibt es ja neue Ideen.

Die Sache mit den global tables in SQL habe ich noch nie benutzt. Aber ich muss gestehen, auf die Schnelle sehe ich auch keinen Unterschied zu einer "normalen" per SQL erstellten Tabelle in QTEMP.

Ich verabschiede mich jetzt erstmal in einen Kurzurlaub!

Euch alles Gute!

LG, Dieter

BenderD
25-05-23, 16:47
Frage: Was würde denn an dieser Stelle gegen dynamisches SQL sprechen?

Den Inhalt des Arrays mit als String aufbereiten (z.B. mit der RPG Built-In-Function %CONCATARR).
Und dann das SQL Statement dynamisch aufbereiten und in den WHERE-Bedingungen bei einer IN-Anweisung den String einbinden (etwa so).


StingArr = %CONCATARR(', ': YourArr);

CmdSQL = 'SELECT ... +
FROM ... +
WHERE YourCol In (' concat :StringArr concat ')' +
...'
//Prepare
//Declare
//Open
//Fetch
//Close



... der O'Hara Effekt.

D*B

Fuerchau
25-05-23, 17:43
Aber Dieter, noch nichts von Replace gehört?
Bei der Stringaufbereitung dann jedes Feld noch per %replace oder noch besser;-) per SQL Replace anzupassen.

GTT werden im Programm deklariert, der Create Table wird automatisch gemacht.
Beim alten Standard ist das halt mit den statischen SQL's das Problem, dass du zur Compile-Zeit eine Tabelle benötigst, die du dann zur Laufzeit ggf. nach QTEMP duplizierst und per OVRDBF umbiegst.
GTT macht den Declare, so dass alle statischen SQL's damit zur Compilezeit umgesetzt werden können. Und die QTEMP wird dann automatisch verwaltet.
Du hast Recht, es ist kein Unterschied, nur der Aufwand ist erheblich geringer.

Ein DS-Array kann nur per Returns Table verwendet werden und ist überhaupt nicht elegant.