PDA

View Full Version : Datenstruktur dynamisch füllen



Seiten : [1] 2

dschroeder
04-08-21, 13:18
Hallo,

ein Kollege hat folgendes Problem:

Er bekommt ein JSON, in dem sich ein Array mit Feldnamen und zugehörigen Feldinhalten befindet. Er würde gerne dieses JSON dynamisch in eine passende, extern definierte Datenstruktur schreiben ohne alle Feldnamen im Programm hart zu codieren. (Es geht letztlich um 3000 Felder, die im JSON vorkommen können). Zusätzlich gibt es eine Tabelle, in der die Feldtypen und Feldlängen beschrieben sind.

Also z.B.
dcl-ds AdressSatz extname('ADRESSE') end-ds;

In der Tabelle Adresse (und damit auch in der Datenstrukur AdressSatz) befinden sich die Felder VORNAME und NACHNAME.
Im JSON befindet sich ebenfalls der Wert "VORNAME" und der Inhalt "Hugo".
Jetzt soll "Hugo" in das Feld "VORNAME" in der Datenstruktur AdressSatz geschrieben werden.
Aber nicht durch harte Verdrahtung, sondern dynamisch, z.B. durch Dynamisches SQL.

Die einzige Lösung, die uns bisher eingefallen ist, ist eine Tabelle "Adresse" in der QTEMP zu erstellen und dynamische SQL-Anweisungen zu erstellen, die einen Datensatz in der Tabelle füllen. Wenn alles gefüllt ist, wird der Datensatz mit statischem SQL wieder ausgelesen und in die Datenstruktur geschoben:

exec sql select * into :AdressSatz from qtemp/adresse fetch first row only.

Das erscheint uns alles sehr umständlich. Hat jemand eine bessere Idee?

Vielen Dank im Voraus.

Dieter

Andreas_Prouza
04-08-21, 13:29
Hallo Dieter,

du kannst das JSON mit SQL wie eine Tabelle lesen.
Somit kannst du das direkt machen:
SELECT * INTO:AdressSatz from JSON_TABLE(dein_JSON, 'doc $', columns(...))

lg Andreas

dschroeder
04-08-21, 13:46
Hallo Andreas,
das geht leider nicht. Im JSON stehen nicht die einzelnen Felder, sondern ein Array der Form:
feldname: "VORNAME", wert: "Hugo",
feldname: "NACHNAME", wert: "Meier"

Vielleich drücke ich mich da falsch aus. Mein Kollege möchte nicht für 3000 mögliche Feldnamen eine JSON_TABLE SQLAnweisung manuell erstellen, sondern die Feldnamen und ihre zugehörigen Werte mittels einer Schleife aus dem JSON auslesen und dann in eine Datenstruktur, die die passenden Feldnamen enthält, schreiben.

Das Problem ist hierbei auch gar nicht das JSON. Er hat die Werte auch schon in 2 Arrays gepackt. Ein Array enthält die Feldnamen, eines die Feldinhalte. Jetzt möchten wir diese Werte in eine Datenstruktur schreiben, ohne die Feldnamen einzeln im Programm anzugeben.

Robi
04-08-21, 13:56
bau dir das doch zusammen

string1
string2

string 1 = vorname, nachname, strasse, ...
string 2 = "hugo", "meier", "musterstrasse", ...

und zum schluss
longstring = 'insert into datei (' + string1 + ') (' + string2 + ')'
EXECUTE IMMEDIATE :longstring

(ganz auf die schnelle, ohne syntaxcheck)


zur Not 50 Felder als insert, alle weiteren in 50er happen als update ...
Robi

dschroeder
04-08-21, 15:15
Ich möchte die Felder ja NICHT in eine Datei schreiben, sondern in eine (extern beschriebene ) Datenstruktur. Das Problem ist, dass dynamisches SQL und Hostvariablen im RPG wohl nicht so gut "harmonieren".

Ich vereinfache das Problem hier mal:

Nehmen wir an, ich müsste in eine RPG-Variable, die BETRAG heißt, den Wert 4711 reinschreiben. Aber ich möchte im RPG den Namen der Variable nicht hard codieren. Dann würde ich mir wünschen, dass so etwas geht:

dcl-s betrag packed(10);
dcl-s anweisung varchar(100);

anweisung = 'set betrag = 4711';
exec sql execute immediate :anweisung

Wenn so etwas klappt, könnten wir unser Problem wahrscheinlich lösen. Aber das funktioniert nicht, weil das SQL-Statement bei der Ausführung die Variable "Betrag" nicht kennt.

Was ginge, wäre natürlich
exec sql set :betrag = 4711;

Aber dann müsste ich ja die Variable "Betrag" fest in meinen Code reinschreiben. Das will ich aber nicht. Ich möchte die Zuweisungsanweisungen per Programm generieren.

BenderD
04-08-21, 15:28
... man kann natürlich schon einen Inhalt per pointer an eine bestimmte Stelle schreiben. Ich würde es hier aber vorziehen per word und excel eine Programmquelle zu generieren und falls ich hundert Varianten hätte, würde ich einen Generator schreiben. Falls jeden Tag zig dazukommen, kann man auch so ein Programm by the fly generieren.

D*B

Fuerchau
04-08-21, 15:41
Dafür ist leider die Sprache (ILE)RPG vollkommen ungeeignet.
Der Feldname dient ja nur uns für die Addressierung des Speichers. Zur Laufzeit spielt letztlich der Name keine Rolle mehr.

Was du machen willst Bedarf am Ende Pointerarithmetik und %Subst().
Per API liest du dir die Feldstruktur der externen Tabelle ein und baust ein weiteres Array auf:
- Name = Name des Feldes
- Pointer = Verweis auf die Basis der externen Struktur + Position des Feldes aus dem API.
- Länge = Länger des Feldes.

Zusätzlich nun 2 Singelfelder:
dcl-s ptr pointer;
dcl-s Feld char(1000) based(ptr);

Hilfsfelder:
dcl-s index int(5);
dcl-s j int(5);

Wenn das Array nach Name sortiert hast, kannst du mit %lookupeq() schnell ein Element auslesen.
Nun kannst du durch dein vorher aufgebautes Array mit den 3000 Namen und Inhalten in einer Schleife folgendes tun:
for j=1 to 3000;
index = %lookupeq(name[j]:PtrArray);
ptr = PtrArray(index).Pointer;
%subst(Feld:1:PtrArray(index).Size) = Value[j];
endfor;

Allerdings ist eine Umwandlung in numerische Felder nur per select/when je Typ mittels %dec() durchführbar, weil die Argumente Stellne/Nachkomma von %dec nur Konstanten sein können.

dschroeder
04-08-21, 16:59
Vielen Dank für eure Antworten.

Unsere reales Problem ist ein zu schreibendes Importprogramm, bei dem ein User aus sehr vielen Feldern auswählen kann, welche er importieren will.

Das Zusammenbauen einer Datenstruktur anhand der Feldpositionen hatte ich mir auch schon überlegt, fand es aber unschön und mein Kollege fragte nach einer "schöneren" Lösung vielleicht mit dynamischem SQL. Eine einfache Lösung scheint es da nicht zu geben.

Ich hätte mir die Lösung mit dem Zusammenbauen der Datenstuktur nicht mit Pointern gebaut. Aber das ist der bessere Weg, wenn ich so darüber nachdenke. Bei der Pointer-Lösung muss ich mir um die Datenformat (z.B. packed) keine großen Gedanken mehr machen, oder?

Ich versuche gerade, den Code von Baldur zu verstehen:

Was macht genau die folgende Anweisung?
ptr = PtrArray(index).Pointer;

Zeigt der ptr auf ein Element im Array?

Mit der Anweisung
%subst(Feld:1:PtrArray(index).Size) = Value[j];
wird die "Datenstruktur" an der passenden Stelle mit dem gewünschten Feldinhalt gefüllt, denke ich. Aber muss ich dazu den Feldinhalt, den ich ja nur als Alpha vorliegen habe, vorher noch in eine korrekte Bytefolge umwandeln? Ein String "Hugo" benötigt genau 4 Bytes, soweit klar. Aber die Zahl 1234 benötigt im gepackten Format ja 3 Bytes. Muss ich mir die 3 Bytes gepackt erst erzeugen oder macht das das Pointerkonstrukt automatisch?

ich wünsche erstmal einen schönen Feierabend!

Fuerchau
04-08-21, 18:16
Das Problem ist ja, dass du wieder nicht dynamisch based Felder auf die Struktur machen kannst.
RPG kann nur auf das Zielfeld zugreifen in dem du den Pointer verschiebst.
Du kannst ihn auch berechnen per

ptr = %addr(DSName) + FeldPosition;

Was Dezimalfelder angeht, so kannst du das nur einzeln lösen:

dcl-s Dec1_0 packed(1:0) based ptr;
dcl-s Dec2_0 packed(2:0) based ptr;
usw.

Dann im Code:
if packed;
select;
when Size = 1,0;
Dec1_0 = %dec(%trim(Valie(j):1:0);
when Size = 2,0;
Dec2_0 = %dec(%trim(Valie(j):1:0);
when Size = 11,2:
Dec11_2 = %dec(%trim(Valie(j):11:2);
endsl;
endif;

BenderD
04-08-21, 19:41
Ich hätte mir die Lösung mit dem Zusammenbauen der Datenstuktur nicht mit Pointern gebaut. Aber das ist der bessere Weg, wenn ich so darüber nachdenke. Bei der Pointer-Lösung muss ich mir um die Datenformat (z.B. packed) keine großen Gedanken mehr machen, oder?
[/COLOR]

... von was träumst Du eigentlich nachts? RPG ist eine Huddel-Proggrammiersprache und eine DS ist ein völlig unkontrollierter Datenhaufen, der mehr oder weniger zufällig im Speicher nebeneinander steht. Es war der feinsinnige Humor der Compiler-Entwickler das Struktur zu nennen.

D*B

PS: ich würde das ganze Gedöns mit if und else in eine procedure verschieben, der man Datentyp, Länge etc mitgibt und die das aufbereitet zurück gibt.