[NEWSboard IBMi Forum]
  1. #1
    Registriert seit
    May 2005
    Beiträge
    103

    Question Dynamisches SQL: Prepare aktualisiert nicht -> Execute mit ursprüngl. Prepare-Inhalt

    Hallo zusammen,

    habe in einem Dialog-Programm ein dynamisches SQL-Insert-Statement eingebaut, welches dem Anwender erlaubt per Auswahl bestimmte Datensätze zu selektieren und diese in eine Ausgabedatei schreibt.

    Die Benutzerauswahl wird in eine Variable SelectStmt gespeichert, diese via

    Exec SQL
    Prepare Schreiben from :SelectStmt;

    und anschließend via

    Exec SQL
    Execute Schreiben;

    ausgeführt.

    Da die Aufbereitung im Dialog und somit in einer Schleife (bis das Programm verlassen wird) durchgeführt wird, kann es vorkommen, dass ein Benutzer (z. B. bei versehentlicher Falscheingabe und Korrektur) mehrmals eine Selektion vornimmt.

    Mein Problem hierbei ist nun, dass stets nur das erste Prepare beim Execute verwendet wird. Sämtliche Änderungen in Variable SelectStmt und anschließendem Prepare bleiben unberücksichtigt.

    An was kann dies liegen?
    ODPs?

    Habe bereits eine Testprozedur mit Erstellung eines Alias geschrieben, um die mehrmalige Verwendung gleichlautender Prepare-Namen zu verifizieren. Auch bei mehrmaligem geänderten SelectStmt, anschließendem Prepare auf gleichen Statement-Namen und Execute funktioniert es.
    Von daher würde ich "falsch" gesetzte Optionen beim Kompilieren ausschließen wollen.

    Vielen Dank für jegliche Hilfestellung und Denkanstöße ;-)

  2. #2
    Registriert seit
    Feb 2001
    Beiträge
    20.258
    Wenn du das Statement nur einmal benötigst, nimm "execute immedate : MyStmt".
    Ansonsten per "Drop Statement MyStmt" bereinien, was sowieso am Ende gemacht werden sollte, falls die SQL-Sitzung nicht beendet wird.
    Dienstleistungen? Die gibt es hier: http://www.fuerchau.de
    Das Excel-AddIn: https://www.ftsolutions.de/index.php/downloads
    BI? Da war doch noch was: http://www.ftsolutions.de

  3. #3
    Registriert seit
    May 2005
    Beiträge
    103
    Hallo Fuerchau,

    vielen Dank für die schnelle Antwort.
    Leider kann ich nicht ganz folgen.
    Wie kann ich dies konkret auf meinen Fall anwenden?
    Drop Statement Schreiben
    Drop Schreiben
    Drop Prepare Schreiben

    funktioniert alles nicht.

    Benötige das Statement aufgrund der Interaktivität mit dem Anwender n-mal. (bis er sich entscheidet, die letzte Selektion getroffen zu haben ;-) )

  4. #4
    Registriert seit
    Feb 2001
    Beiträge
    20.258
    Stimmt, ein Drop Statement gibts nicht. Ich kann allerdings auch nichts finden, dass man den Prepare durchaus mehrmals machen kann.
    Allerdings hilft dir ggf. die Gültigkeit des Statements etwas:
    Prepared statement persistence: All prepared statements are destroyed when:118
    v A CONNECT (Type 1) statement is executed.
    v A DISCONNECT statement disconnects the connection with which the prepared
    statement is associated.
    v A prepared statement is associated with a release-pending connection and a
    successful commit occurs.
    v The associated scope (job, activation group, or program) of the SQL statement
    ends.

    Wenn du denn unbedingt mit Prepare arbeiten willst, so lagere es in eine untergeordnete Funktion/Prozedur aus. So kann diese den Prepare wiederholen.

    Wie gesagt, alternativ kannst du auch den "Execute immediate" verwenden, da hast du die Restriktion nicht.
    Dienstleistungen? Die gibt es hier: http://www.fuerchau.de
    Das Excel-AddIn: https://www.ftsolutions.de/index.php/downloads
    BI? Da war doch noch was: http://www.ftsolutions.de

  5. #5
    Registriert seit
    May 2005
    Beiträge
    103
    Bin leider auf das Prepare angewiesen, da ich in Abhängigkeit der Benutzereingabe über ein Array die zu summierenden Felder im Statement aufbereite. (... sum(' + %trim(AryAbsMon) + ') ... )
    Dass ein Prepare wiederverwendbar ist konnte ich jedoch bereits über meine Testprozedur verifizieren.
    Ich suche also weiter nach einer Lösung.

    Vielen Dank trotzdem für deine Unterstützung! :-)

  6. #6
    Registriert seit
    May 2002
    Beiträge
    1.121
    Bau doch dein SQL einfach zusammen
    SelectStmt = blabla bla
    Exec SQL Execute Immediate :SelectStmt

    Geht auch ganz ohne den Prepare

    Gruß
    Ronald

  7. #7
    Registriert seit
    Feb 2001
    Beiträge
    20.258
    Warum wehrst du dich gegen das Execute Immediate?
    Noch mal als Hinweis:
    Ein Prepared Statement lässt sich beliebig oft im aktuellen Scope ausführen.
    Ein Prepare auf ein Statement ist im Scope nur 1 x möglich, ein Löschen der Ressource ist wohl nicht vorgesehen. Also musst du den Scope verlassen.

    Da du das zusammengebaute Statement jedoch nur 1x ausführen willst, kannst du halt "Execute Immediate" verwenden. Hierbei wird die Syntax eben jedes mal neu geprüft und anschließend ausgeführt. Benötigte Ressorcen werden hinterher verworfen.
    M.a.W: Ein "Execute Immedate" ist ebenso beliebig oft ausführbar, dauert halt ein paar Millisekunden länger.
    Dienstleistungen? Die gibt es hier: http://www.fuerchau.de
    Das Excel-AddIn: https://www.ftsolutions.de/index.php/downloads
    BI? Da war doch noch was: http://www.ftsolutions.de

  8. #8
    Registriert seit
    Mar 2002
    Beiträge
    5.288
    ...
    - ein wenig mehr Info (code!!!) erleichtert Antworten ungemein
    - execute immediate versus prepare execute ist für Einmal Statements sogar schneller
    - ein prepare sollte bei dem (vage) beschriebenen Ablauf den vorherigen prepare wegschmeißen
    -- was sagt denn der SQLCODE und das Joblog nach dem prepare?
    -- wie sieht es mit dem PTF Stand aus, neue Releases bringen meist im SQL Bereich etliche Bugs mit
    - meist lassen sich solche Aufgabenstellungen (variable Auswahlen) mit Parameter Markern und prepare - execute using besser lösen.

    D*B
    AS400 Freeware
    http://www.bender-dv.de
    Mit embedded SQL in RPG auf Datenbanken von ADABAS bis XBASE zugreifen
    http://sourceforge.net/projects/appserver4rpg/

  9. #9
    Registriert seit
    May 2005
    Beiträge
    103
    Vielen Dank für die rege Beteiligung!

    Hier die Antworten auf die Anmerkungen/Fragen:

    Wehre mich gegen das Execute Immediate, weil ich nicht glaube, dass sich meine Anwendung hiermit realisieren lässt. Gehe nach wie vor davon aus, dass ich um das Prepare (ob in Subprozedur oder direkt) nicht umhin komme.
    Aber urteilt selbst:


    // Select-Statement aufbereiten
    SelectStmt = 'insert into libneu.dateineu -

    Select ' + '''' + MandAlpha + '''' + ', ' + %char(Jahr) + ', -

    ' + %char(
    MonVon) + ', ' + %char(MonBis) + ', vstnr, -

    vsgeba, vsgebi, vsmark, vsprhg, vsprgr, -

    vskdgr, vsvtr, vskdnr, vsvbnr,-

    sum(' + %trim(AbsMonate) + '), sum(' + %trim(UmsMonate) + '), -

    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '' '', '' '', '' '', 0, 0, 0, 0 -

    from Statistik inner join Kundenstamm on vskdnr = kdnr -

    where vsbla = ''A'' and kdanzp <> 4 -

    and vsmrze not in(''54'', ''98'') and vsmatg = ''0001'' -

    group by ' + '''' +
    MandAlpha + '''' + ', ' + %char(Jahr) + ', -

    ' + %char(MonVon) + ', ' + %char(MonBis) + ', vstnr, -

    vsgeba, vsgebi, vsmark, vsprhg, vsprgr, -

    vskdgr, vsvtr, vskdnr, vsvbnr -

    having sum(' + %trim(
    AbsMonate) + ') <> 0 or -

    sum(' + %trim(
    UmsMonate) + ') <> 0';


    ExecSQL
    Prepare BuchenAbsAT from :SelectStmt;


    // Ausführen vorbereitetes SQL-Statement
    ExecSQL
    Execute BuchenAbsAT;


    Die orange markierten Felder sind Eingaben von Benutzern.
    Die rot markierten Felder sind Inhalte, die sich auf Basis der gewählten Zeiträume aus den entsprechenden Datenbankfelder zusammensetzen.

    Hier ein bisschen mehr Code zum besseren Verständnis:
    // Initialisieren Array Feldnamen AbsatzMonate
    aryAbsMon(1) = 'vimja2';
    aryAbsMon(2) = 'vimfe2';
    aryAbsMon(3) = 'vimmz2';
    aryAbsMon(4) = 'vimap2';
    aryAbsMon(5) = 'vimma2';
    aryAbsMon(6) = 'vimjn2';
    aryAbsMon(7) = 'vimjl2';
    aryAbsMon(8) = 'vimau2';
    aryAbsMon(9) = 'vimse2';
    aryAbsMon(10) = 'vimok2';
    aryAbsMon(11) = 'vimno2';
    aryAbsMon(12) = 'vimde2';
    aryAbsMon(13) = 'vimja1';
    aryAbsMon(14) = 'vimfe1';
    aryAbsMon(15) = 'vimmz1';
    aryAbsMon(16) = 'vimap1';
    aryAbsMon(17) = 'vimma1';
    aryAbsMon(18) = 'vimjn1';
    aryAbsMon(19) = 'vimjl1';
    aryAbsMon(20) = 'vimau1';
    aryAbsMon(21) = 'vimse1';
    aryAbsMon(22) = 'vimok1';
    aryAbsMon(23) = 'vimno1';
    aryAbsMon(24) = 'vimde1';
    aryAbsMon(25) = 'vimja0';
    aryAbsMon(26) = 'vimfe0';
    aryAbsMon(27) = 'vimmz0';
    aryAbsMon(28) = 'vimap0';
    aryAbsMon(29) = 'vimma0';
    aryAbsMon(30) = 'vimjn0';
    aryAbsMon(31) = 'vimjl0';
    aryAbsMon(32) = 'vimau0';
    aryAbsMon(33) = 'vimse0';
    aryAbsMon(34) = 'vimok0';
    aryAbsMon(35) = 'vimno0';
    aryAbsMon(36) = 'vimde0';
    // Initialisieren Array Feldnamen UmsatzMonate
    aryUmsMon(1) = 'viwja2';
    aryUmsMon(2) = 'viwfe2';
    aryUmsMon(3) = 'viwmz2';
    aryUmsMon(4) = 'viwap2';
    aryUmsMon(5) = 'viwma2';
    aryUmsMon(6) = 'viwjn2';
    aryUmsMon(7) = 'viwjl2';
    aryUmsMon(8) = 'viwau2';
    aryUmsMon(9) = 'viwse2';
    aryUmsMon(10) = 'viwok2';
    aryUmsMon(11) = 'viwno2';
    aryUmsMon(12) = 'viwde2';
    aryUmsMon(13) = 'viwja1';
    aryUmsMon(14) = 'viwfe1';
    aryUmsMon(15) = 'viwmz1';
    aryUmsMon(16) = 'viwap1';
    aryUmsMon(17) = 'viwma1';
    aryUmsMon(18) = 'viwjn1';
    aryUmsMon(19) = 'viwjl1';
    aryUmsMon(20) = 'viwau1';
    aryUmsMon(21) = 'viwse1';
    aryUmsMon(22) = 'viwok1';
    aryUmsMon(23) = 'viwno1';
    aryUmsMon(24) = 'viwde1';
    aryUmsMon(25) = 'viwja0';
    aryUmsMon(26) = 'viwfe0';
    aryUmsMon(27) = 'viwmz0';
    aryUmsMon(28) = 'viwap0';
    aryUmsMon(29) = 'viwma0';
    aryUmsMon(30) = 'viwjn0';
    aryUmsMon(31) = 'viwjl0';
    aryUmsMon(32) = 'viwau0';
    aryUmsMon(33) = 'viwse0';
    aryUmsMon(34) = 'viwok0';
    aryUmsMon(35) = 'viwno0';
    aryUmsMon(36) = 'viwde0';

    // Füllen Variable für Absatz
    Zaehler = IndexVon;
    AbsMonate = *blanks;
    dow Zaehler <= IndexBis;
    AbsMonate = %trim(AbsMonate) + ' + ' + aryAbsMon(Zaehler);
    Zaehler = Zaehler + 1;
    enddo;

    // Füllen Variable für Umsatz
    Zaehler = IndexVon;
    UmsMonate = *blanks;
    dow Zaehler <= IndexBis; UmsMonate = %trim(UmsMonate) + ' + ' + aryUmsMon(Zaehler);
    Zaehler = Zaehler + 1;
    enddo;

    Der Inhalt der Variable
    UmsMonate stellt sich bei Auswahl des Jahres 2016 und der Monate von 9 bis 12 bspw. folgendermaßen dar:
    EVAL UmsMonate
    UMSMONATE =
    ....5...10...15...20...25...30...35...40...45...50 ...55...60
    1 '+ viwse0 + viwok0 + viwno0 + viwde0 '
    61 ' '
    121 ' '
    181 ' '

    Da es (leider) noch keine Umsätze von 9-12 in 2016 gibt (SQLCODE 100 nach Execute BuchenAbsAT) und der Anwender nun seinen Fehler bemerkt, ändert er anschließend das Jahr von 2016 auf 2015 und bestätigt erneut seine Eingabe.
    Nun stellt sich der Wert der Variable
    UmsMonate zum Zeitpunkt des Prepare BuchenAbsAT from :SelectStmt; wie folgt dar:
    UMSMONATE =
    ....5...10...15...20...25...30...35...40...45...50 ...55...60
    1 '+ viwse1 + viwok1 + viwno1 + viwde1 '
    61 ' '
    121 ' '
    181 ' '

    Auch das SelectStmt zum Zeitpunkt des 2. Prepares ist richtig gefüllt:

    SELECTSTMT =
    ....5...10...15...20...25...30...35...40...45...50 ...55...60
    1 'insert into libneu.dateineu Select '007', 2015, 9, 12'
    61 ', vstnr, vsgeba, vsgebi, vsmark, vsprhg, vsprgr, vskdg'
    121 'r, vsvtr, vskdnr, vsvbnr, sum(+ vimse1 + vimok1 + vimno1 +'
    181 ' vimde1), sum(+ viwse1 + viwok1 + viwno1 + viwde1), 0, 0,'
    241 ' 0, 0, 0, 0, 0, 0, 0, 0, ' ', ' ', ' ', 0, 0, 0, 0 from Statistik'
    301 ' inner join Kundenstamm on vskdnr = kdnr where vsbla '
    361 '= 'A' and kdanzp <> 4 and vsmrze not in('54', '98') and v'
    421 'smatg = '0001' group by '007', 2015, 9, 12, vstnr, '
    481 'vsgeba, vsgebi, vsmark, vsprhg, vsprgr, vskdgr, vsvtr, vs'
    541 'kdnr, vsvbnr having sum(+ vimse1 + vimok1 + vimno1 + vimd'
    601 'e1) <> 0 or sum(+ viwse1 + viwok1 + viwno1 + viwde1) <> 0'

    Der SQL-Code nach dem 2. Prepare ist 0, also i. O.

    Nach dem erneuten Execute BuchenAbsAT ist der SQL-Code jedoch wieder 100, weil er keine Sätze finden konnte.
    Kopiere ich jedoch den Inhalt der Variablen SelectStmt in den SQL-Editor, so bekomme ich folgerichtig die Absätze für die Monate 9-12 in 2015 angezeigt....

    Release V7R1M0
    PTF-Stand: TL13037

    Um die Geschwindigkeit geht es mir im 1. Step noch gar nicht. Mir wäre eher daran gelegen, dass es überhaupt funktioniert :-/


  10. #10
    Registriert seit
    May 2005
    Beiträge
    103
    STOPP an ALLE!!!

    Habe es gefunden und es ist mir eigentlich fast zu peinlich es zuzugeben....

    Hatte noch eine rudimentäre Statistik in meiner vorrangigen Testbibliothek.

    SORRY für eure sinnlos gestohlene Zeit!!

    Übrigens vermisse ich hier den Smiley, der sich mit dem Hammer auf den Kopf haut. Hätte diesen eben sicherlich inflationär eingesetzt

Similar Threads

  1. Dynamisches embedded SQL
    By Tschabo in forum NEWSboard Programmierung
    Antworten: 10
    Letzter Beitrag: 11-03-21, 09:14
  2. MONMSG: Inhalt abfragen
    By JoergHamacher in forum NEWSboard Programmierung
    Antworten: 4
    Letzter Beitrag: 03-02-16, 11:47
  3. Dynamisches SQL bauen in RPG
    By labm in forum NEWSboard Programmierung
    Antworten: 8
    Letzter Beitrag: 07-05-15, 07:55
  4. SQL Select Statement - Execute dauert sehr lange
    By max40 in forum NEWSboard Java
    Antworten: 19
    Letzter Beitrag: 20-02-15, 17:39
  5. TCP/IP-Leitwege - Dynamisches Eintragen verhindern?
    By mott in forum IBM i Hauptforum
    Antworten: 7
    Letzter Beitrag: 18-09-02, 15:42

Tags for this Thread

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • You may not post attachments
  • You may not edit your posts
  •