Abhängiges Verarbeiten zweier ResultSets

Hallo miteinander,

ich habe eine Frage zu einem Vorgehen: In einem Programm nutze ich zwei ResultSets. Mein “linkes” ResultSet arbeite ich step-by-step ab. Dabei prüfe ich immer, ob Name & Vorname der beiden Pointer (linkes & rechtes ResultSet) identisch sind. Falls das der Fall ist, wird das rechte ResultSet auch verarbeitet und der Pointer nach vorne verschoben. Problem dabei ist, dass zu einem Eintrag auf der linken Seite, mehrere (oder auch keine) Einträge auf der rechten Seite gehen.

Ich brauche also bei der Verarbeitung des linken ResultSets (immer wenn ich den Pointer gerade verschiebe) eine Schleife, die solange durch mein rechtes ResultSet läuft, solange Name & Vorname mit dem Name & Vorname des linken ResultSets übereinstimmen und solange next() == true.

Ich hatte an sowas gedacht:

    while (linkesRS.next() {
       while(rechtesRS.getString("Name").equals(linkesRS.getString("Name"))
         && rechtesRS.getString("Vorname").equals(linkesRS.getString("Vorname"))
       ) {
            //verarbeite rechtes RS und schiebe Pointer nach vorne
            // ...
            rechtesRS.next();
      }
    }

Ansich läuft das alles ganz prima. Nachteil ist aber, dass der Pointer des rechten RS einfach immer weitergeschoben wird. Damit kann es ganz am Ende zu einem Fehler kommen (Erschöpfte Ergebnismenge).

Ich bräuchte daher euren Tipp!

Danke

Mit isAfterLast() testen, ob man am Ende ist und dann halt nichts machen?

Aber ansich spricht nichts gegen dieses While-Konstrukt oder? Also, dass ich in der While-Bedingung prüfe, ob die Felder übereinstimmen.

Felder-Abfrage ist das Wesen des ResultSets,
neben Ablage in Variablen auch häufig in Bedingungen zu finden (soviel mehr gibt es an Möglichkeiten eh kaum :wink: )
ob if oder Schleife macht nicht viel Unterschied,
also ja, ziemlich normaler Code

grundsätzlich könnte man wie fast überall anmerkern, von ResultSets Abstand zu nehmen,
nur in Objekte wie Person mit Name/ Vorname übertragen + Listen
(übrigens das was bei Hibernate/ HQL normalerweise rauskommt)

falls nicht zu viel Programmieraufwand und zu viel Last für Umwandlungsarbeit, evtl. Arbeitsspeicher sprengende Datenmengen,
dann hätte es die üblichen Vorteile:

  • einfacheren Code getName().equals(getName()), dabei sicherer objektorientiert, kein Fehler wegen Tippfehler im String „Nane“
  • Liste ohne derart merkwürdige Fehler am Ende
  • Logik-Code von ResultSet/ Datenbank unabhängig, funktioniert auch in anderen Situationen

aber nix dramatisches, eher graue Theorie

Abhängig vom konkreten Kontext: Ist es nicht möglich die Abfragen der Resultsets in eine zu packen, so dass man gar nicht mehr prüfen muss, sondern nur noch ein Set ausliest?

Hey Leute,

erstmal danke für eure Hilfe. Es ist schon bemerkenswert, dass man hier nach nur wenigen Minuten solche Antworten bekommt. Im Java-Forum warte ich immer noch auf meine erste Antwort bzgl. dieser Frage. Danke!!

Da ich die Daten aus dem ResultSet nicht wirklich verarbeite, sondern jede Zeile nur genau einmal „anfasse“, wollte ich mir das parsen in Objekte nun sparen. Mir wurde halt gesagt, dass man ResulSets mit while(rs.next())… durchläuft. Daher auch meine Frage! Ich bin nämlich der Meinung, dass dies bei meinem rechten RS nicht funktioniert. Klar ist next() eine wichtige Bedingung, aber zudem müssen meine Felder identisch sein, sonst darf hier gar nichts gemacht werden. Würde ich beim rechten ResultSet immer mit while(rs.next()) durchlaufen,würde das dazu führen, dass der Pointer immer eins weitergeschoben wird. Das wäre nicht in meinem Interesse. :wink:

Danke schonmal euch allen!

Wäre das hier also ein sinniges Konstrukt?

while (linkesRS.next() {
       while(rechtesRS.getString("Name").equals(linkesRS.getString("Name"))
         && rechtesRS.getString("Vorname").equals(linkesRS.getString("Vorname"))
       ) {
            // verarbeite rechtes RS
            // ...

            // Schiebe Pointer nach vorne, falls möglich
           if(!rechtesRS.isAfterLast()) { 
             rechtesRS.next();
           }
      }
    }

Ich erwarte, dass Du damit schon in der ersten Iteration auf die Nase fällst weil (bei Oracle) auch für das “rechte” ResultSet .next() aufgerufen werden muss, bevor man auf die Daten darin zugreifen kann. Damit sähe die Schleife bei mir so aus:while (linkesRS.next() { while(rechtesRS.next() && rechtesRS.getString("Name").equals(linkesRS.getString("Name")) && rechtesRS.getString("Vorname").equals(linkesRS.getString("Vorname")) ) { // verarbeite rechtes RS // ... } }
bye
TT

Was spricht gegen einen Join auf den zwei Spalten? Etwa so:
[SQL]SELECT tblA., tblB. FROM tblA INNER JOIN tblB ON (tblA.Name = tblB.Name AND tblA.Vorname = tblB.Vorname)[/SQL]
ggf. mit einem LEFT JOIN statt dem INNER JOIN, falls auch die Zeilen benötigt werden, zu denen es keine Entsprechung in tblB gibt.

Wie cmrudolph geschrieben hat, würde ich auch mit einem LEFT JOIN oder INNER JOIN arbeiten — außerdem solltest du dein Datenbankdesign überdenken. Vor- und Nachname sind keine guten Felder um einen Datensatz eindeutig zu identifizieren. Gewöhne dir lieber an mit IDs zu arbeiten (fortlaufende Nummer, GUID, …), dass spart dir über kurz oder lang einiges an ärger. Außerdem: was machst du wenn eine Person heiratet und sich der Nachname ändert - dann musst das in anscheinend in mehreren Tabellen anpassen. Wenn du aber mit Inhaltsunabhängigen IDs arbeitest, dann hast du nur eine Tabelle.

zum Java-Code unabhängig anderer Lösungsmöglichkeiten

[QUOTE=Timothy_Truckle;94865]Ich erwarte, dass Du damit schon in der ersten Iteration auf die Nase fällst weil (bei Oracle) auch für das “rechte” ResultSet .next() aufgerufen werden muss, bevor man auf die Daten darin zugreifen kann. Damit sähe die Schleife bei mir so aus:while (linkesRS.next() { while(rechtesRS.next() && rechtesRS.getString("Name").equals(linkesRS.getString("Name")) && rechtesRS.getString("Vorname").equals(linkesRS.getString("Vorname")) ) { // verarbeite rechtes RS // ... } }
bye
TT[/QUOTE]
diese Doppelschleife geht nicht, denn ein bestimmtes Element aus rechtesRS soll mehrfach gegen Einträge von linkesRS geprüft werden, bis Übereinstimmung gefunden wird,
nicht vor jedem Vergleich zwingend mit next() weitergehen

1x next() vor den Doppelschleifen ist nicht allzu schlimm, danach reicht das next() in der inneren Schleife sofern für das aktuelle Element von rechtesRS eine Übereinstimmung gefunden wird

Verstehe ich das richtig, dass Du nicht nur mehrere “Rechts” einem “Links” zuordnen willst sondern auch umgekehrt?

Dann solltest Du in einer zusetzlichen ersten Schleife eine Liste der “Rechts”-DTOs erzeugen und diese dann innerhalb der “Links”-Schleife für jedes “Links” vollständig durchiterieren. Falls “Rechts” (wesentlch) mehr Elemente hat dann eben umgekehrt. Solange die Anzahl der Elemente nicht in die Millionen geht sollte das performant genug sein…

bye
TT

ich (als letzter zuvor vielleicht mit ‘Du’ angesprochen) kann die Aufgabe nur mutmaßen, doppelte Iterationen scheinen dann aber unnötig,
man kann ruhig alles umwandeln, links wie rechts, danach würde sich aber an der Schleifenverarbeitung kaum was ändern

meine Vorstellung:
links:
A
B
C
D
E

rechts:
C1
C2
E1
E2

gewünscht ist, die Cs und Es jeweils zu kombinieren

die Verarbeitung beginnt mit next() auf A fürs linke ResultSet, rechts muss schon auf ersten Eintrag C1 stehen,
nun darf rechts nicht weiterlaufen, auch nicht wenn links auf B geht, rechts muss warten,

wenn links C erreicht hat, dann wird C1 akzeptiert + next() innerhalb der inneren Schleife, C2 genauso, schließlich steht rechts auf E1,
dann geht links weiter
usw.

da ist die Schleifenstellung so genau richtig

Ich glaube SlaterB hat mein Problem erkannt. So hatte ich es letztendlich jetzt auch gelöst. 1x next() davor und dann immer bei Übereinstimmung in der inneren schleife ein next(). Wobei ich bei der inneren Schleife zusätzlich auf !isAfterLast() prüfe.

Beim Join bin ich nicht ganz sicher, ob das so funktioniert. Die beiden Statements haben nämlich nur 2 identische Spalten. Das sind die Spalten, die ich für die Überprüfung benötige. Ansonsten haben die Zeilen der beiden Statements ganz unterschiedliche Spalten und Werte.

Danke euch nochmal! Und super, dass man hier geholfen bekommt - anders als im java-forum.

[QUOTE=Vivid]
Beim Join bin ich nicht ganz sicher, ob das so funktioniert. Die beiden Statements haben nämlich nur 2 identische Spalten. Das sind die Spalten, die ich für die Überprüfung benötige. Ansonsten haben die Zeilen der beiden Statements ganz unterschiedliche Spalten und Werte.
…[/QUOTE]

Ich bin mir fast sicher, das ein Join funktionieren würde - es gibt nur sehr selten Fälle, bei denen man in der Verknüpfung zweier Tabellen etwas nicht mit SQL lösen kann. Eine Doppel-Iteration wie du sie machst ist fast immer unnötig.

Ja, du hast sicherlich Recht. Wusste halt nicht, wie kostenintensiv der Join werden würde. Wir reden hier schon über 7.000 - 10.000 Zeilen in Summe.

ggf. musst du einen oder mehrere Indizes auf die Spalten legen, die im Vergleich verwendet werden - dann ist das kein Problem (wesentlich schneller und sparsamer als die Client-seitige Lösung bei der zwei Resultsets gleichzeitig offen sind).

Ohne Indizes kannst du natürlich mit einem Join auf 10000*10000 Zeilen leicht deine DB abwürgen - je nach Situation.

Ich würde an deiner Stelle einfach das ganze nochmal mit einem entsprechendem JOIN probieren. Wenn du nur Datensätze bearbeiten willst, bei denen es mind. einen Wert in der rechten Tabelle gibt - dann nimmste einen INNER JOIN … ansonsten einen LEFT JOIN.

Hast du es denn ausprobiert? Und falls ja: ein Join lässt sich auf verschiedene Weisen beschleunigen.
[ol][li]normalisierte Tabellen benutzen (siehe @Tomate_Salat s Post in #10) und dann auf der Namens-ID statt auf den Stringfeldern verknüpfen[/li][*]einen Index auf den Joinspalten erstellen[/ol]