Sql-Joins oder "Mache ich Sinn?"
Peter
- datenbank
Liebe Forumler und Forumlerinnen,
ich poste hier, weil ich einfach keine Informationen auf meine Fragen im Netz finde und ich hier immer sehr gut beraten worden bin.
Ich habe folgende Grundsatzfrage: Ich arbeite gerade an einem System in PHP, das einige komplexe Anfragen an eine MYSQL 4 (später vielleicht auch 5er) Datenbank absetzen soll. Dabei benötige ich Joins über diverse Table, wenn die gesicherten DatenObjekte in 1:1 Beziehungen stehen.
Bislang habe ich dazu meine SQL-Statements vom System generieren lassen, das klappte auch recht gut, führt aber dazu, daß die Statements wirklich extrem lang werden. Beispiel als Extremfall:
SELECT
a.uid as a_uid, a.name as a_name, a.eigenschaft1 as a_eigenschaft1 [... es folgen xx Eigenschaften ...],
b.uid as b_uid, b.name as b_name, b.eigenschaft1 as b_eigenschaft1 [... es folgen xy Eigenschaften ...],
c.uid as c_uid, c.name as c_name, c.eigenschaft1 as c_eigenschaft1 [... es folgen xz Eigenschaften ...],
FROM
TableA a, TableB b, TableC c
WHERE
a.buid = b.uid
AND
a.cuid = c.uid
AND
[... sonstige Bedingungen ...]
Die Generierung dieser Statements ist manchmal hakelig, aber funktioniert. Danach kann ich aus dem jeweiligen Result meine Objekte kreieren.
Nun meine Fragen... :)
Gibt es eine einfachere Möglichkeit, diverse gleich benannte Spalten ( wie zB 'uid' und 'name' im Beispiel ) in verschiedenen Tabellen in einem Query abzufragen? Also sowas wie "SELECT a.* as a_obj, b.* as b_obj" ?
Würden mir hier irgendwelche (Left, Right, Outer, Inner) - Joins weiterhelfen? Kennt jemand gute Artikel zur Verwendung von SQL-Joins? Alles was ich finde sind recht einfache Beispiele, in denen zwei unterschiedliche Eigenschaften verglichen werden... das hilft mir irgendwie nicht.
Hat jemand generell Ideen oder Tipps, wie ich solche komplexen Statements anders aufbauen könnte? Ich habe leider wenige direkte Ansprechpartner für solche Fragen, und ich bin nie so ganz sicher, ob dieser Ansatz nicht totaler Wahnsinn ist... :) und vielleicht einfacher gelöst werden könnte.
Vielen Dank für Eure Hilfe,
Peter
SELECT
a.uid as a_uid, a.name as a_name, a.eigenschaft1 as a_eigenschaft1 [... es folgen xx Eigenschaften ...],
b.uid as b_uid, b.name as b_name, b.eigenschaft1 as b_eigenschaft1 [... es folgen xy Eigenschaften ...],
c.uid as c_uid, c.name as c_name, c.eigenschaft1 as c_eigenschaft1 [... es folgen xz Eigenschaften ...],
Wozu du das machst wäre auch sinnvoll zu Wissen.
FROM
TableA a, TableB b, TableC c
WHERE
a.buid = b.uid
AND
a.cuid = c.uid
AND
[... sonstige Bedingungen ...]
Das dürfte das langsamste sein was du machen kannst. Du hast hier ganz einfache join Bedingungen erstellst aber erst eine Kreuztabelle.
- Gibt es eine einfachere Möglichkeit, diverse gleich benannte Spalten ( wie zB 'uid' und 'name' im Beispiel ) in verschiedenen Tabellen in einem Query abzufragen? Also sowas wie "SELECT a.* as a_obj, b.* as b_obj" ?
Meines Wissens nein
- Würden mir hier irgendwelche (Left, Right, Outer, Inner) - Joins weiterhelfen? Kennt jemand gute Artikel zur Verwendung von SQL-Joins? Alles was ich finde sind recht einfache Beispiele, in denen zwei unterschiedliche Eigenschaften verglichen werden... das hilft mir irgendwie nicht.
Du brauchst hier nicht mehr als ein einfaches Beispiel, warum hast du es nicht umgesetzt?
- Hat jemand generell Ideen oder Tipps, wie ich solche komplexen Statements anders aufbauen könnte? Ich habe leider wenige direkte Ansprechpartner für solche Fragen, und ich bin nie so ganz sicher, ob dieser Ansatz nicht totaler Wahnsinn ist... :) und vielleicht einfacher gelöst werden könnte.
Durchaus berechtigte frage, nur läßt sich aus dem Schnipsel nicht klar erkennen was du eigentlich tun willst (ausser eine riesige Datenmenge erzeugen)
Struppi.
SELECT
a.uid as a_uid, a.name as a_name, a.eigenschaft1 as a_eigenschaft1 [... es folgen xx Eigenschaften ...],
b.uid as b_uid, b.name as b_name, b.eigenschaft1 as b_eigenschaft1 [... es folgen xy Eigenschaften ...],
c.uid as c_uid, c.name as c_name, c.eigenschaft1 as c_eigenschaft1 [... es folgen xz Eigenschaften ...],Wozu du das machst wäre auch sinnvoll zu Wissen.
Ok, sagen wir "a" sei ein reales Produkt (mit verschiedenen Eigenschaften) aus einem Material "b" (ebenfalls mit x Eigenschaften) einer Firma "c" mit Adresse, Ansprechpartner etc.
Sowohl Produkt, Material als auch Firma sind in PHP als Objekte in entsprechenden Klassen modelliert. Diese Objekte lege ich (eben über generierte SQL-Statements) komplett in der Datenbank ab.
Nun gibt es ( zugegebenerweise selten ) Situationen, in denen ich anhand eines Produktes auch die anderen "anhängenden" Objekte aus der Datenbank ziehen will/muß. Das heißt, ich benötige alle Eigenschaften aller verknüpften Objekte, um diese in PHP erstellen zu können.
Genau das soll diese Anfrage ausdrücken... :)
FROM
TableA a, TableB b, TableC c
WHERE
a.buid = b.uid
AND
a.cuid = c.uid
AND
[... sonstige Bedingungen ...]Das dürfte das langsamste sein was du machen kannst. Du hast hier ganz einfache join Bedingungen erstellst aber erst eine Kreuztabelle.
Ja, aber wenn einzelne Spalten gleiche Namen haben, zerfräst mir das doch wieder das Result oder? Zum Beispiel wird a.name durch b.name in den resultierenden Rows überschrieben, wenn ich diese nicht durch "AS" a_name etc. mit einem alias versehe...
Beispiel:
TableA: uid | name | b_uid
TableB: uid | name
SELECT * FROM TableA
INNER JOIN TableB ON TableA.b_uid = TableB.uid;
Die Anfrage wird zwar ausgeführt, aber im resultierenden Array ist in der Spalte 'name' eben der Name aus TableB. Der Name aus TableA existiert nicht mehr. Ich will beide.
Du brauchst hier nicht mehr als ein einfaches Beispiel, warum hast du es nicht umgesetzt?
Wenn mein Problem so einfach zu lösen ist, dann schubs mich bitte in die richtige Richtung... :) Ich sehs nich.
SELECT
a.uid as a_uid, a.name as a_name, a.eigenschaft1 as a_eigenschaft1 [... es folgen xx Eigenschaften ...],
b.uid as b_uid, b.name as b_name, b.eigenschaft1 as b_eigenschaft1 [... es folgen xy Eigenschaften ...],
c.uid as c_uid, c.name as c_name, c.eigenschaft1 as c_eigenschaft1 [... es folgen xz Eigenschaften ...],Wozu du das machst wäre auch sinnvoll zu Wissen.
Ok, sagen wir "a" sei ein reales Produkt (mit verschiedenen Eigenschaften) aus einem Material "b" (ebenfalls mit x Eigenschaften) einer Firma "c" mit Adresse, Ansprechpartner etc.
Also erstmal vorweg, du hast verschiedene Tabellen in denen immer die gleichen Spalten mit unterschiedlichen werten sind?
Da würde ich von einem schlechtne Datenbankdesign ausgehen.
FROM
TableA a, TableB b, TableC c
WHERE
a.buid = b.uid
AND
a.cuid = c.uid
AND
[... sonstige Bedingungen ...]Das dürfte das langsamste sein was du machen kannst. Du hast hier ganz einfache join Bedingungen erstellst aber erst eine Kreuztabelle.
Ja, aber wenn einzelne Spalten gleiche Namen haben, zerfräst mir das doch wieder das Result oder? Zum Beispiel wird a.name durch b.name in den resultierenden Rows überschrieben, wenn ich diese nicht durch "AS" a_name etc. mit einem alias versehe...
Ok, also gleiche Spaltennamen
Beispiel:
TableA: uid | name | b_uid
TableB: uid | nameSELECT * FROM TableA
INNER JOIN TableB ON TableA.b_uid = TableB.uid;Die Anfrage wird zwar ausgeführt, aber im resultierenden Array ist in der Spalte 'name' eben der Name aus TableB. Der Name aus TableA existiert nicht mehr. Ich will beide.
Ist hier ein LEFT JOIN nicht sinnvoller?
Willst du alle Einträge in TableA und die dazu gehörigen Daten in TableB oder willst du auch die einträge aus TableB die keine entsprechung in TableA haben?
Ich vermute du willst:
SELECT *, a.name AS a_name, b.name AS b_name FROM TableA AS a LEFT JOIN TableB AS b ON a.b_uid = b.uid;
Wobei ich versuchen würde name genauer zu definieren, z.b. Produktname, Lieferantename
und die id's versuchen gleich zu bennen, also uid für z.b. eine userid und b_id für .... (Produkt ID?)
Dann kannst du die Abfrage noch mehr vereinfachen:
SELECT *, a.name AS a_name, b.name AS b_name FROM TableA AS a LEFT JOIN TableB AS b USING(uid);
Du brauchst hier nicht mehr als ein einfaches Beispiel, warum hast du es nicht umgesetzt?
Wenn mein Problem so einfach zu lösen ist, dann schubs mich bitte in die richtige Richtung... :) Ich sehs nich.
Es kommt halt immer darauf an, was du willst.
Struppi.
Also erstmal vorweg, du hast verschiedene Tabellen in denen immer die gleichen Spalten mit unterschiedlichen werten sind?
Da würde ich von einem schlechtne Datenbankdesign ausgehen.
Hm... ok. Mein Problem würde sich mächtig vereinfachen, wenn jede Spalte einen eindeutigen Namen hat. Ich Hundehirn.
Beispiel:
TableA: uid | name | b_uid
TableB: uid | nameSELECT * FROM TableA
INNER JOIN TableB ON TableA.b_uid = TableB.uid;Die Anfrage wird zwar ausgeführt, aber im resultierenden Array ist in der Spalte 'name' eben der Name aus TableB. Der Name aus TableA existiert nicht mehr. Ich will beide.
Ist hier ein LEFT JOIN nicht sinnvoller?
Willst du alle Einträge in TableA und die dazu gehörigen Daten in TableB oder willst du auch die einträge aus TableB die keine entsprechung in TableA haben?Ich vermute du willst:
SELECT *, a.name AS a_name, b.name AS b_name FROM TableA AS a LEFT JOIN TableB AS b ON a.b_uid = b.uid;
Wobei ich versuchen würde name genauer zu definieren, z.b. Produktname, Lieferantename
und die id's versuchen gleich zu bennen, also uid für z.b. eine userid und b_id für .... (Produkt ID?)
Ne, ich wollte in diesem Fall tatsächlich den INNER JOIN. Aber ich glaube, mein größtes Problem ist tatsächlich die mehrfache Verwendung derselben Spaltennamen... und das läßt sich recht simpel lösen!
Ich danke Dir vielmals!
Gruß, Peter
yo,
Das dürfte das langsamste sein was du machen kannst. Du hast hier ganz einfache join Bedingungen erstellst aber erst eine Kreuztabelle.
wie kommst du auf die idee, dass hier eine kreuztabelle erstellt werden würde ?
Ilja
Hi,
kurzes Intermezzo:
Dabei benötige ich Joins über diverse Table, wenn die gesicherten DatenObjekte in 1:1 Beziehungen stehen.
Wenn die Objekte in einer 1:1-Beziehung zueinander stehen, nennt man sie "Spalten". Den JOIN von Spalten des selben Datensatzes führt ein modernes DBMS ohne Dein Zutun aus.
Cheatah
Hi,
kurzes Intermezzo:
Dabei benötige ich Joins über diverse Table, wenn die gesicherten DatenObjekte in 1:1 Beziehungen stehen.
Wenn die Objekte in einer 1:1-Beziehung zueinander stehen, nennt man sie "Spalten". Den JOIN von Spalten des selben Datensatzes führt ein modernes DBMS ohne Dein Zutun aus.
Cheatah
Vielen Dank... macht Mysql 4 sowas und wenn, wie? Gibt´s da ein Stichwort, nachdem ich suchen kann?
Gruß, Peter
Hi,
Wenn die Objekte in einer 1:1-Beziehung zueinander stehen, nennt man sie "Spalten". Den JOIN von Spalten des selben Datensatzes führt ein modernes DBMS ohne Dein Zutun aus.
Vielen Dank... macht Mysql 4 sowas
was ich damit eigentlich sagen wollte ist: Eine 1:1-Beziehung ist das mit Abstand simpelste, was eine Datenbank beherrscht. Selbst das CSV-Format basiert darauf. Datenbanken beherrschen das seit den 60er Jahren (IIRC).
Cheatah
was ich damit eigentlich sagen wollte ist: Eine 1:1-Beziehung ist das mit Abstand simpelste, was eine Datenbank beherrscht. Selbst das CSV-Format basiert darauf. Datenbanken beherrschen das seit den 60er Jahren (IIRC).
Ich dachte, der Begriff "1:1-Beziehung" drückt aus, daß Datensatz A aus Tabelle A über genau einen Fremdschlüssel mit Datensatz B in Tabelle B verknüpft ist... im Gegensatz zu 1:n oder n:m - Beziehungen.
Sollte das stattdessen 1:1 Relation heissen, nehme ich es auch hin. :)
Gruß,
Peter
Hi,
Ich dachte, der Begriff "1:1-Beziehung" drückt aus, daß Datensatz A aus Tabelle A über genau einen Fremdschlüssel mit Datensatz B in Tabelle B verknüpft ist...
mit _genau einem_ Datensatz in Tabelle B, ja. Und das wird nicht über Fremdschlüssel o.ä. gemacht, sondern über Spalten.
Sollte das stattdessen 1:1 Relation heissen, nehme ich es auch hin. :)
Nein, es ist einfach nur so, dass das Vorhandensein einer 1:1-Beziehung (über mehrere Tabellen) ein sehr, sehr starkes Indiz für ein undurchdachtes DB-Layout ist. Welchen Sinn macht es, Informationen eines Datensatzes in einen eineindeutig verknüpften Datensatz einer fremden Tabelle auszulagern?
Cheatah
Hi,
Ich dachte, der Begriff "1:1-Beziehung" drückt aus, daß Datensatz A aus Tabelle A über genau einen Fremdschlüssel mit Datensatz B in Tabelle B verknüpft ist...
mit _genau einem_ Datensatz in Tabelle B, ja. Und das wird nicht über Fremdschlüssel o.ä. gemacht, sondern über Spalten.
bei MS SQL Server gibt es "1:1"-Beziehungen. Die werden vermutlich über Fremdschlüssel implementiert sein, aber ich habs mir noch nicht genau angeschaut.
Nein, es ist einfach nur so, dass das Vorhandensein einer 1:1-Beziehung (über mehrere Tabellen) ein sehr, sehr starkes Indiz für ein undurchdachtes DB-Layout ist. Welchen Sinn macht es, Informationen eines Datensatzes in einen eineindeutig verknüpften Datensatz einer fremden Tabelle auszulagern?
Wenn die "1:1"-Beziehung nullable ist, macht es schon Sinn.
Rolf
Hallo Peter,
Ich habe folgende Grundsatzfrage: Ich arbeite gerade an einem System in PHP, das einige komplexe Anfragen an eine MYSQL 4 (später vielleicht auch 5er) Datenbank absetzen soll.
Bitte beachte folgende Einschränkung bezüglich MySQL:
MySQL kann erst ab Version 5.0.1 einigermaßen richtig mit Klammern umgehen, eine weitere Verbesserung erfolgte in Version 5.0.12, siehe Handbuch.
INNER JOINs bereiten MySQL auch in niedrigeren Versionen keine Probleme, aber bei komplexeren Outer Joins kommen schlicht und einfach völlig falsche Resultate heraus. Gesetzte Klammern werden _nicht_ berücksichtigt.
Wenn Du wirklich komplexere Join-Operationen hast, dann rate ich Dir _dringend_ von MySQL unter 5.0.12 ab. Ich habe in Deinen Ausführungen allerdings keinen komplexeren Join gesehen, nur einfache INNER JOINS und Unkenntnis der JOIN-Syntax. Bei Deinem Beispiel könntest Du auch die USING-Syntax verwenden, auf die in dem von mir verlinkten Handbuchabschnitt eingegangen wird.
- Würden mir hier irgendwelche (Left, Right, Outer, Inner) - Joins weiterhelfen? Kennt jemand gute Artikel zur Verwendung von SQL-Joins?
selbstverständlich:
Einführung Joins
Fortgeschrittene Joins
Freundliche Grüße
Vinzenz
Hallo Vinzenz,
Wenn Du wirklich komplexere Join-Operationen hast, dann rate ich Dir _dringend_ von MySQL unter 5.0.12 ab. Ich habe in Deinen Ausführungen allerdings keinen komplexeren Join gesehen, nur einfache INNER JOINS und Unkenntnis der JOIN-Syntax.
Erwischt. :) Ich habe da zu wenig Plan...
Danke vielmals für Anmerkungen und Links! Ich werde mir das mal zu Gemüte führen!
Gruß,
Peter