Insert innerhalb eines Selects

Hi!

Gibt’s hier auch Leute, die sich mit DB2 auskennen?

Folgendes Problem:

Ich lese Daten aus einer Tabelle einer DB2-Datenbank mittels dynamischem SQL. Dafür baue ich mir den Cursor auf und stelle für das Fetch entsprechende Host-Variablen zur Verfügung.

Nun hole ich den ersten Datensatz ab und lese mit Schlüsselfeldern in einer Zieltabelle, ob der Satz bereits vorhanden ist. Wenn dem so ist, führe ich ein Update durch. Wird der Satz nicht gefunden, soll ein Insert durchgeführt werden. Danach hole ich mittels Fetch den nächsten Datensatz.

Sowohl Update wie Insert funktionieren problemlos. Das Problem tritt jedoch nach dem Insert auf. Der Fetch nach dem Insert geht mit SQLCODE = -518 kaputt (EXECUTE Statement enthält ein nicht korrekt präpariertes Statement).

Diese Fehlermeldung ist eigentlich Quatsch, da das SQL bereits vorher über PREPARE der Datenbank bekanntgegeben wurde und ja auch schon funktioniert hat.

Ich vermute, dass das Insert einen Autocommit ausführt und dadurch mein Cursor zerschossen wird.

Kann man da irgendwas machen?

Grüße
Heinrich

Hallo,

du könntest natürlich auf Oracle umstellen :smile:, die kann das.
Ansonsten kannst du ja eine temporäre Tabelle oder ein tabellenwertiges Attribut benutzen, in die Du die Schlüssel aus dem Cursor reinschreibst. Das sollte es beides auch unter DB2 geben.

Ausserdem kannst Du vermutlich auch die EXCEPTION abfangen. Dann könntest Du das Insert ganz normal machen und in die Exception (bei Oracle dup_val_on_index) mit einem Update weitermachen.

Hoffe, das hilft Dir.

Gruß

Peter

Hi!

du könntest natürlich auf Oracle umstellen :smile:, die kann das.
Ansonsten kannst du ja eine temporäre Tabelle oder ein
tabellenwertiges Attribut benutzen, in die Du die Schlüssel
aus dem Cursor reinschreibst. Das sollte es beides auch unter
DB2 geben.

Ausserdem kannst Du vermutlich auch die EXCEPTION abfangen.
Dann könntest Du das Insert ganz normal machen und in die
Exception (bei Oracle dup_val_on_index) mit einem Update
weitermachen.

Anscheinend habe ich mich unklar ausgedrückt. Es geht nicht um einen Dup-Key-Fehler beim Insert, sondern (vermutlich) um einen Auto-Commit beim Insert, der mir den Zustand meines SQLs in der Datenbank zerhaut.

Ich weiß ja nicht im Detail, wie das bei Oracle-DBs ist, aber beim Lesen von Daten unter DB2 mittels dynamischem SQL muss ich mir zunächst einen Cursor deklarieren, dann mein Select-Statement aufbauen und dieses mittels Prepare der Datenbank bekanntgeben (beim statischen SQL ist das per Programm nicht erforderlich, da es hier Bind-Routinen gibt). Jetzt kennt die Datenbank meine Datenanforderung und ich kann den definierten Cursor öffnen (d.h. die gesamte Datenpaket wird mir zur Verfügung gestellt). Die einzelnen Sätze greifen ich per Fetch ab und stelle die gelesenen Werte in Host-Variablen.

So weit, so gut.

Nun bastel ich mir die Daten für einen Insert zurecht, schreibe einen Satz in eine zweite Tabelle und versuche, mittels Fetch den nächsten Satz zu lesen. Und bekomme die Fehlermeldung, das SQL sei nicht korrekt mittels Prepare der Datenbank bekannt gemacht worden.

Das riecht danach, als ob der Insert mit einem Auto-Commit das SQL in der Datenbank weggehauen hat.

Tja, was tun?

Grüße
Heinrich

Hallo,

ein Autocommit könnte aus der Art, wie du die Session aufbaust entstehen. Odbc-Verbindungen z.B. sind in der Regel im Autocommit modus. Den transaktionsmodus kannst du aber setzen.

wenn du nicht lesen - schreiben - lesen - schreiben kannst, warum dann nicht:

alles lesen - alles schreiben.

Gruß

Peter

PS: dup_val_on_index könnte deine Prozedur evtl elegant ersetzen. Wenn ich Dich recht verstanden habe, prüfst du erst ab, ob ein Datensatz existiert. Wenn er existiert, machst du ein UPDATE, sonst ein INSERT.

Genau das macht ja die Exception:

Du machst - blind - ein INSERT. Ist der Datensatz vorhanden, löst die DB eoine Exception aus. Die kannst Du aber abfangen und dann einfach ein UPDATE machen.

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hi!

ein Autocommit könnte aus der Art, wie du die Session aufbaust
entstehen. Odbc-Verbindungen z.B. sind in der Regel im
Autocommit modus. Den transaktionsmodus kannst du aber setzen.

wenn du nicht lesen - schreiben - lesen - schreiben kannst,
warum dann nicht:

alles lesen - alles schreiben.

Würde einen dynamischen Array bedeuten, je nachdem wie viele Datensätze vorhanden sind (zwischen 0 und 900.000)

PS: dup_val_on_index könnte deine Prozedur evtl elegant
ersetzen. Wenn ich Dich recht verstanden habe, prüfst du erst
ab, ob ein Datensatz existiert. Wenn er existiert, machst du
ein UPDATE, sonst ein INSERT.

Genau das macht ja die Exception:

Du machst - blind - ein INSERT. Ist der Datensatz vorhanden,
löst die DB eoine Exception aus. Die kannst Du aber abfangen
und dann einfach ein UPDATE machen.

Der Fehler tritt nicht wegen einer Exception auf, sondern eben weil es _keine_ Exception gibt:

Ich stelle mir mittels dynamischem SQL eine Antwortmenge bereit (z.B. 10.000 Datensätze). Dann hole ich mir den ersten Datensatz ab, prüfe die Werte und führe mit Teildaten des gelesenen Satzes einen Insert auf eine zweite Tabelle durch. Der Insert meldet _keinen_ Fehler! Dann will ich den zweiten Satz aus dem gelesenen Datenbestand holen, und jetzt sagt die Datenbank. ich würde mit einem SQL lesen wollen, das nicht durch ein „Prepare“ der Datenbank bekannt gemacht wurde.

Nochmal: es geht _nicht_ um das Fehler-Handling bei einem Dup-Key-Error.

Ich vermute, dass nach dem Insert eine Aktualisierung der System-Einträge erfolgt und dabei die Informattionen in der DB über den Zustand meines SQLs verloren gehen.

Grüße
Heinrich

Hi!

ein Autocommit könnte aus der Art, wie du die Session aufbaust
entstehen. Odbc-Verbindungen z.B. sind in der Regel im
Autocommit modus. Den transaktionsmodus kannst du aber setzen.

wenn du nicht lesen - schreiben - lesen - schreiben kannst,
warum dann nicht:

alles lesen - alles schreiben.

Würde einen dynamischen Array bedeuten, je nachdem wie viele
Datensätze vorhanden sind (zwischen 0 und 900.000)

Bei so vielen Daten würde ich eine temporäre Tabelle nehmen.

PS: dup_val_on_index könnte deine Prozedur evtl elegant
ersetzen. Wenn ich Dich recht verstanden habe, prüfst du erst
ab, ob ein Datensatz existiert. Wenn er existiert, machst du
ein UPDATE, sonst ein INSERT.

Genau das macht ja die Exception:

Du machst - blind - ein INSERT. Ist der Datensatz vorhanden,
löst die DB eoine Exception aus. Die kannst Du aber abfangen
und dann einfach ein UPDATE machen.

Der Fehler tritt nicht wegen einer Exception auf, sondern eben
weil es _keine_ Exception gibt:

Ich stelle mir mittels dynamischem SQL eine Antwortmenge
bereit (z.B. 10.000 Datensätze). Dann hole ich mir den ersten
Datensatz ab, prüfe die Werte und führe mit Teildaten des
gelesenen Satzes einen Insert auf eine zweite Tabelle durch.
Der Insert meldet _keinen_ Fehler! Dann will ich den zweiten
Satz aus dem gelesenen Datenbestand holen, und jetzt sagt die
Datenbank. ich würde mit einem SQL lesen wollen, das nicht
durch ein „Prepare“ der Datenbank bekannt gemacht wurde.

Nochmal: es geht _nicht_ um das Fehler-Handling bei einem
Dup-Key-Error.

Ich vermute, dass nach dem Insert eine Aktualisierung der
System-Einträge erfolgt und dabei die Informattionen in der DB
über den Zustand meines SQLs verloren gehen.

Das kann ich mir beim besten Willen nicht vorstellen. Kann es sein, dass zwischenzeitlich deine erste Tabelle verändert wird? Durch einen Trigger oder so?

Findest DU keinen anderen Weg als dynamisches SQL?

Grüße
Heinrich