Problem mit DB-Abfrage

Ich komm irgendwie mit meiner Datenbankabfrage (JDBC, PostgreSQL) nicht weiter.

Und zwar möchte ich 2 Tabellen miteinander verbinden und abfragen. Eine Tabelle person mit Personendaten (ID, Nachname, Vorname…), in welcher auch 2 int-Werte (Fremdschlüssel zur anderen Tabelle User) für User-IDs sind, welche die Person angelegt bzw. zuletzt geändert haben.

Die Daten aus der Datenbanktabelle person sollen ausgelesen und in ein Objekt der Klasse Person geschreiben werden.

Bisher hatte ich in meiner Person-Klasse einfach die beiden int-Werte als Felder, und zu diesen dann erst später die jeweiligen User-Daten aus der DB geholt, wenn diese gebraucht wurden. Nun kam ich nach einem Hinweis im Forum auf die Idee, in der Person-Klasse die beiden int-Felder (mit den User-IDs) gegen User-Objekte auszutauschen, so dass diese User-Daten direkt mit in der Person-Klasse vorhanden sind.

Wenn ich nur 1 User-Feld hätte, könnte ich einfach einen JOIN mit den beiden Tabellen machen und über Fremdschlüssel in person mit Primärschlüssel in user verbinden. Aber ich hab ja 2 User-Felder (angelegt und zuletzt geändert), die auch unterschiedlich sein können. Und die beiden User muss ich ja anhand der jeweiligen ID aus der Tabelle User holen.

Geht das irgendwie mit einer Abfrage und einem JOIN, oder muss ich da mehrere Abfragen an die DB schicken? Also zuerst die beiden UserIDs holen und mit diesen dann jeweils nochmal eine SQL-Abfrage losschicken, um an die Userdaten zu kommen? Mit Subselects kann ich ja immer nur nach 1 Spalte in der Tabelle User fragen, d.h. da die Tabelle User mehrere Spalten hat (etwa 10), müsste ich 20 Subselects einbauen. Das kommt mir etwas umständlich vor.

Oder ist das mit den User-Objekten im meiner Person-Klasse grundsätzlich nicht so gut und ich sollte lieber wieder zu den int-Werten wechseln?

Ich hoffe, ich hab mein Problem einigermassen verständlich geschildert (ansonstne fragt halt nochmal nach), und es kann mir hier jemand weiterhelfen.

wenn ich das richtig verstanden hab willst du doch einfach das hier machen
[sql]
SELECT * FROM user u, anderetabelle a WHERE u.user_id = a.user_id;
[/sql]
oder hab ich das falsch verstanden?

Hmm, nicht ganz. Wie gesagt, ich hab 2 Felder mit User-IDs als Fremdschlüssel in meiner Tabelle person. Einmal der User, welcher die Person in der Tabelle angelegt hat, und dann für den User, welcher die letzte Änderung gemacht hat. Das können auch zwei unterschiedliche User sein. Dieser Fremdschlüssel (integer user_id_insert und integer user_id_change) sind dann die Primärschlüssel in der Datenbanktabelle user.

Die Tabelle user selber hat auch wieder mehrere Felder wie Namen, Kürzel usw. der User. Und diese Daten möchte ich als User-Objekte in meine Person-Objekte anlegen. Vorher waren in der Person-Klasse nur 2 int-Werte mit den User-IDs drin.

achso na dann das ist auch einfach, ach ich muss mal wieder mehr mit Datenbanken machen, das macht einfach so viel Spaß

[sql]select * FROM person p, user uc, user ue WHERE p.user_id_insert = uc.user_id AMD p.user_id_change = ue.user_id[/sql]

Du hast da jetzt einfach 3 Tabellen miteinander verknüpft? Einmal die Tabelle person und zweimal die Tabelle user, mit jeweils anderen Bezeichnern? Hmm, das könnte evtl. die Lösung sein. Ich werde das nachher mal testen (dauert noch ne Weile) und dann Bescheid geben.

Ich find ja Datenbanken auch spannend, aber manchmal häng ich da fest und komm nicht weiter. Gerade wenn mehrere Tabellen verknüpft werden müssen…

jep genau und durch den Alias kannst du auf jede einzelne gut zugreifen

Hey cool, scheint zu funktionieren. Vielen Dank! Das wusste ich auch noch nicht, dass ich nach FROM auch zweimal die gleiche Tabelle (mit unterschiedlichem Bezeichner) angeben kann. Das Problem ist jetzt nur, wie kann ich die Felder der beiden Bezeichner unterscheiden? Weil ich hab ja jetzt jedes Feld zweimal, einmal von uc und einmal von ue.

Kann man eigentlich beim ResultSet den Bezeichner mit angeben? Also z.B. rs.getString[“uc.kuerzel”] und rs.getString[“ue.kuerzel”]?

jep das kannst du machen
jep das kannst du machen :smiley:

ich bevorzuge aber die Möglichkeit hier
[sql]SELECT p.id AS person_id, uc.user_id user_insert_id, uc.username AS user_insert_name … FROM person p, USER uc, USER ue WHERE p.user_id_insert = uc.user_id AMD p.user_id_change = ue.user_id [/sql]
So weißt du genau die Namen

OK, stimmt. Hab auch mal gehört, dass mit dem * nicht so gut wäre. Hab halt in der Tabelle person 32 Felder und für user 12 (weil Tabelle zweimal dann 24). Wird halt ein sehr langer SQL-Befehl, aber wahrscheinlich ist es wirklich besser und übersichtlicher. Mal schauen, werde das wohl erst morgen mal konkret da einbauen.

ja vor allem fragst du so auch nur ab was du brauchst

Ja, in dem Fall brauch ich aber wohl eh alles…

Bist du denn sicher, dass du hier einen vernünftigen Entwurf hast? Tabellen mit 32 Feldern sind meist nicht sonderlich gut entworfen …
Warum willst du das überhaupt auflösen? Ich denke, dass hier grundsätzlich die Wahl über FKs wesentlich besser ist.

[QUOTE=Aru]Bist du denn sicher, dass du hier einen vernünftigen Entwurf hast? Tabellen mit 32 Feldern sind meist nicht sonderlich gut entworfen …
Warum willst du das überhaupt auflösen? Ich denke, dass hier grundsätzlich die Wahl über FKs wesentlich besser ist.[/QUOTE]

Schlechter Entwurf?
Ich hab z.B. schon Tabellen von namhaften ERP-Anbietern
mit weit mehr als 255 Feldern gesehen. DA sollte man
bei der Abfrage tatsächlich überlegen, ob ein * wirklich
Sinn macht. :wink:

[QUOTE=Aru]Bist du denn sicher, dass du hier einen vernünftigen Entwurf hast? Tabellen mit 32 Feldern sind meist nicht sonderlich gut entworfen …
Warum willst du das überhaupt auflösen? Ich denke, dass hier grundsätzlich die Wahl über FKs wesentlich besser ist.[/QUOTE]

Na ja, hab ja einen Entwurf mit mehreren Tabellen. Und für diese Tabelle mit den Personendaten brauch ich wohl schon diese 32 Felder.

Das mit dem “Auflösen” bin ich mir im Moment garnicht mehr so sicher. Ich muss mir da nochmal Gedanken machen, ob es sinnvoller ist, nur den FK (int) in den Personenobjekten zu speichern, oder das beim Lesen der Daten aus der Datenbank gleich in ein Objekt umzuwandeln und in der Person als Variable anzulegen. Vielleicht muss ich nochmal schauen, wo ich diese Daten denn überhaupt brauche.

Hatte das mal irgendwo in Java-Forum gelesen. Gibt es da grundsätzliche Überlegungen und Tipps, was besser ist?

Auch wenn es ohne das Buch nicht soo hilfreich ist, verschafft sich Martin Fowlers Katalog der Patterns aus dem Buch „Patterns of Enterprise Application Architecture“ einen groben Überblick.
Um deine Frage zu beantworten, ja es gibt dazu grundsätzliche Überlegungen - denen widmet Fowler einen nicht unerheblichen Teil des oben genannten Werkes.
Interessant sind in deinem Fall wohl die Patterns aus dem Bereich „Object-Relational Behavioral Patterns“ und „Object-Relational Structural Patterns“.

Das was du beschreibst, entspricht wahrscheinlich dem dort beschriebenen LazyLoad, wobei du ein Proxy-Objekt mit den Usern anlegst, die erst bei Bedarf das echte Userobjekt aus der Datenbank laden. Das dürfte (je nach Größe der Datenbank) die Datenbank auch enorm entlasten, weil ein Join zwischen drei Tabellen schon ganz schön auf den Speicher geht.
Mit der PostgreSQL-Datenbank habe ich bisher noch nicht viel gearbeitet und weiß daher nicht, wie geschickt die Query optimiert wird. Aber so wie sie dort formuliert ist, führt das im schlimmsten Fall zu einer temporären Tabelle der Größe (Anzahl Zeilen in der PersonenTabelle x Anzahl Zeilen in der UserTabelle x Anzahl Zeilen in der UserTabelle), aus der mit einem Full-Table-Scan nur die relevanten Zeilen herausgefiltert werden. Dazu sollte man sich mal ausgeben lassen, was die Datenbank wirklich macht.

Danke für diese Hinweise…