PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Python/Jython - Problem mit Bearbeitung von DbResutSets


Mr_Snakefinger
2012-09-05, 22:05:29
N'Abend zusammen...

Ich hätte da mal ein Problem mit der Bearbeitung von DbResultSets aus einer DB-Abfrage mit Python/Jython.

Normalerweise mache ich das wie folgt:
ResultSet = client.executeQuery(<SQL-Statement>)
while ResultSet.next():
value1 = ResultSet.getString('Column1')
# do something else

Funktioniert auch soweit, wie gewünscht.

Blöderweise habe ich jetzt das Problem, dass ich das gleiche ResultSet mehrfach durchlaufen muss, was aber nach dem ersten Durchlauf mit next() nicht mehr möglich ist.

Frage ist also, wie ich das ResultSet duplizieren kann, so dass das ursprüngliche Set erhalten bleibt, und ich quasi auf einer Kopie arbeite (und das originae ResultSet nach dem ersten Durchlauf eben nochmal in eine temporäre Variable dupliziere).

Eine einfache Zuweisung á la
ResultSet = client.executeQuery(<Query>)
Temp = ResultSet
tut es nicht.

Auch copy.copy() und copy.deepcopy() habe ich bereits probiert, das schlägt jeweils mit der folgenden Meldung fehl:

- un(shallow)copyable object of type org.python.core.PyJavaInstance
- un-deep-copyable object of type org.python.core.PyJavaInstance

Im Netz hab ich schon was von clone() gelesen, aber die Funktion kennt Python/Jython irgendwie nicht. Eventuell fehlt auch nur ein Import?

Wer hat noch eine Idee?

Sephiroth
2012-09-05, 22:23:38
Blöderweise habe ich jetzt das Problem, dass ich das gleiche ResultSet mehrfach durchlaufen muss, was aber nach dem ersten Durchlauf mit next() nicht mehr möglich ist.
und was hindert dich daran das einfach zu tun, wenn du gerade das resultset in deiner schleife hast?

while ResultSet.next():
while was_auch_immer:
# mach was mehrmals mit dem gleichen resultset

oder speicher dir das was du vom resultset brauchst in eine variable ...

Mr_Snakefinger
2012-09-05, 22:39:16
und was hindert dich daran das einfach zu tun, wenn du gerade das resultset in deiner schleife hast?

Sobald ich mit next() in die nächste Zeile des Sets springe, ist die vorhergehende Zeile nicht mehr verfügbar. Und Zurückspringen ist nicht: "This resultset is forward_only / readonly".


oder speicher dir das was du vom resultset brauchst in eine variable ...

Das wäre ein Workaround, wobei das dann darauf hinausläuft, dass ich das komplette Set in eine (mehrdimensionale) Liste kopieren müsste, was bei knapp 20 Spalten und knapp 300.000 Zeilen auch eher unschön ist.

Nagelbrett
2012-09-05, 23:22:12
Wenn du es nicht komplett im Speicher zwischenhalten willst, bleibt dir aber wohl nichts anderes übrig, als das Query nochmal auszuführen, da vermutlich das ResultSet selbst schon nur ein Generator ist der dann Zeile für Zeile von der Datenbank entgegen nimmt und dir zurückliefert.

Warum musst du es denn überhaupt mehrmals durchlaufen? Kannst du es nicht so machen, wie von Sephiroth vorgeschlagen, dass du du das, was du mehrmals pro Datensatz machen willst, einfach innerhalb einer äußeren Schleife über das ResultSet machst?

Sephiroth
2012-09-05, 23:23:26
du "weißt" also erst hinterher das du eine der früheren zeilen brauchst?

Mr_Snakefinger
2012-09-05, 23:49:41
Wenn du es nicht komplett im Speicher zwischenhalten willst, bleibt dir aber wohl nichts anderes übrig, als das Query nochmal auszuführen, da vermutlich das ResultSet selbst schon nur ein Generator ist der dann Zeile für Zeile von der Datenbank entgegen nimmt und dir zurückliefert.

Das ResultSet wird schon komplett von der DB geliefert und in die Variable "ResultSet" gespeichert. Dieses ResultSet ist aber halt ein eigener Datentyp und nicht etwa eine Liste von Strings o.ä., weswegen bspw. nur durch spezielle Funktionen (derer es nicht viele gibt) darauf zugegriffen werden kann. Aus dem gleichen Grund kann es auch nicht einfach kopiert werden (siehe Fehlermeldungen oben).
Darüber hinaus hat dieses Konstrukt eben den Nachteil, dass das ResultSet nur in eine Richtung durchlaufen werden kann und jede Zeile nach dem Wechsel auf die darauf folgende Zeile nicht mehr referenzierbar ist.

Von daher bleiben tatsächlich nur zwei Möglichkeiten:
- Manuell in eine Liste ablegen, die unveränderlich ist und mehrfach genutzt werden kann
- Die Abfrage an die Datenbank mehrfach absetzen

Möglichkeit 1 ist unschön aber noch mit vertretbarem Aufwand machbar.
Möglichkeit 2 fällt raus, weil es sich bei der DB um eine produktive DB handelt, die wir nicht zu häufig mit Queries stressen sollten, die derart große ResultSets liefern. Aktuell arbeiten wir noch auf der Entwickler-DB mit einem kleineren Datenbestand, aber beim Produktivsystem handelt es sich teilweise um Tabellen mit mehreren Millionen Zeilen und da bewegen wir uns schon in einem kritischen Bereich.

Vielleicht noch als Ergänzung zum besseren Verständnis:
Es dreht sich nicht nur um eine einzelne Abfrage, sondern tatsächlich handelt es sich um 15-20 Queries, die miteinander in Beziehung stehen. Einen Teil dieser Beziehungen können wir sicherlich durch JOINs auflösen, aber dennoch bleibt der Kern bestehen:

- es gibt eine DB Abfrage, welche x Zeilen zurückliefert, in welcher Hosts/Server-Informationen stehen
- jeder Host/Server hat mit ihm verbundene Informationen, welche in unterschiedlichen Tabellen liegen

Bedeutet: Für jede Zeile in der Host/Server-Tabelle muss ich die Tabellen der verbundenen Daten mehrfach durchlaufen, um die Keys gegeneinander abzugleichen und dann damit etwas zu tun.

Von daher fallen mehrfache Queries an die DB per se aus.

Warum musst du es denn überhaupt mehrmals durchlaufen? Kannst du es nicht so machen, wie von Sephiroth vorgeschlagen, dass du du das, was du mehrmals pro Datensatz machen willst, einfach innerhalb einer äußeren Schleife über das ResultSet machst?

Ich bin mir gerade nicht sicher, wie das Konstrukt aussehen soll...

du "weißt" also erst hinterher das du eine der früheren zeilen brauchst?

Vielleicht konnte die rudimentäre Beschreibung oben etwas Licht ins Dunkle zu bringen?!

Ansnsten: Ich weiß schon vorher, dass ich die Zeilen mehrfach brauche. Ich weiß vorher nur nicht genau wie oft und wann genau.

Vielleicht geht ein einfaches Beispiel:

Die "äußere Tabelle" hat Infos zu den einzelnen Hosts/Servern.
Die "innere Tabelle" hät Infos zu darauf installierter Software.

Ich nehme jetzt die äußere Tabelle und setze darin eine zweite Schleife (bspw. while innereTabelle.next()), wo ich bestimmte Felder aus der äußeren mit der inneren Tabelle abgleiche.
Den Spaß darf ich dann aber für jede Zeile der äußeren Tabelle machen, was es eben erforderlich macht, die innere Tabelle mehrfach zu durchlaufen. Und das ganze nicht nur für eine innere Tabelle, sondern für vielleicht 10, 15 oder noch mehr.

Ich weiß, das Ganze ist etwas umständlich beschrieben, aber ich darf leider öffentlich keine Produkt-, Hersteller-Namen etc. nennen... :frown:

Nagelbrett
2012-09-05, 23:58:31
Das ResultSet wird schon komplett von der DB geliefert und in die Variable "ResultSet" gespeichert.
Ja hast recht.
Darüber hinaus hat dieses Konstrukt eben den Nachteil, dass das ResultSet nur in eine Richtung durchlaufen werden kann und jede Zeile nach dem Wechsel auf die darauf folgende Zeile nicht mehr referenzierbar ist.

Ist das JDBC?
Von http://docs.oracle.com/javase/tutorial/jdbc/basics/retrieving.html:Note that the default sensitivity of a ResultSet is TYPE_FORWARD_ONLY,
[...]
The field ResultSet.TYPE_SCROLL_SENSITIVE creates a ResultSet object whose cursor can move both forward and backward relative to the current position and to an absolute position.

Hilft das vielleicht weiter?

Mr_Snakefinger
2012-09-06, 00:05:09
Hilft das vielleicht weiter?

Muss ich mir morgen Vormittag mal in Ruhe ansehen, ist jetzt doch etwas spät geworden. Aber danke schonmal :)

Aber es handelt sich zumindest um eine Oracle-DB, die über eine JDBC-Connection abgefragt wird, ja.

Sephiroth
2012-09-06, 22:13:50
Aber es handelt sich zumindest um eine Oracle-DB, die über eine JDBC-Connection abgefragt wird, ja.
Das nächste mal erwähnst du sowas besser gleich ;)

http://docs.oracle.com/javase/6/docs/api/java/sql/ResultSet.html#absolute%28int%29

PatkIllA
2012-09-06, 22:17:57
Die "äußere Tabelle" hat Infos zu den einzelnen Hosts/Servern.
Die "innere Tabelle" hät Infos zu darauf installierter Software.

Ich nehme jetzt die äußere Tabelle und setze darin eine zweite Schleife (bspw. while innereTabelle.next()), wo ich bestimmte Felder aus der äußeren mit der inneren Tabelle abgleiche.
Den Spaß darf ich dann aber für jede Zeile der äußeren Tabelle machen, was es eben erforderlich macht, die innere Tabelle mehrfach zu durchlaufen. Und das ganze nicht nur für eine innere Tabelle, sondern für vielleicht 10, 15 oder noch mehr.Klingt so, als ob du das auch direkt jeweils mit einem Join (oder mehreren) von der Datenbank selbst machen lassen kannst.