mySQL: komplizierter (?) Select
Andreas Cloos
- datenbank
0 Vinzenz0 Klaus Mock
Hallo Zusammen,
ich habe drei Tabellen, über die ich eine verknüpfte Abfrage ausführen möchte. Die Tabellen enthalten unter anderem folgende Spalten:
projects_overview: cust_id (Kundennummer), p_start, p_end (Projektanfang und -ende)
customer_data: cust_id, faktura_satz_id
faktura_saetze: faktura_satz_id, faktura_op_rev
Der Select soll nur alle Daten aus der projects_overview auslesen, wenn zum Kunden des Projektes eine faktura_satz_id existiert, die im Feld faktura_op_rev einen bestimmten Text enthält (das können mehrere faktura_satz_ids sein).
Es kann nicht vorkommen, daß in einer der Tabllen leere Zeilen oder Felder vorhanden sind. Left join etc. ist daher meiner Meinung nach nicht notwendig.
Mein Versuch sah so, liefert aber nichts zurück (der Vergleich über das Datum (Projektanfang und -ende) ist aber nicht die Fehlerquelle, wenn ich ihn rausnehme, bleibt das Ergebnis das selbe)...
SELECT po.* FROM projects_overview AS po, customer_data AS cd, faktura_saetze AS fs WHERE (('1041375600' <= unix_timestamp(po.p_end) AND '1072825200' >= unix_timestamp(po.p_end)) OR ('1041375600' <= unix_timestamp(po.p_start) AND '1072825200' >= unix_timestamp(po.p_start)) OR ('1041375600' <= unix_timestamp(po.p_start) AND '1072825200' <= unix_timestamp(po.p_end))) AND cd.cust_id = po.p_cust_id AND fs.faktura_satz_id = cd.faktura_satz_id AND fs.faktura_op_rev LIKE 'Ext. Erlöse'
Wo ist der Fehler?
Hallo» Hallo Zusammen,
ich habe drei Tabellen, über die ich eine verknüpfte Abfrage ausführen möchte. Die Tabellen enthalten unter anderem folgende Spalten:
projects_overview: cust_id (Kundennummer), p_start, p_end (Projektanfang und -ende)
customer_data: cust_id, faktura_satz_id
faktura_saetze: faktura_satz_id, faktura_op_revDer Select soll nur alle Daten aus der projects_overview auslesen, wenn zum Kunden des Projektes eine faktura_satz_id existiert, die im Feld faktura_op_rev einen bestimmten Text enthält (das können mehrere faktura_satz_ids sein).
Zusammenfassung:
Alle Spalten aus projects_overview
Bedingung: Bestimmter Wert in faktura_saetze.faktura_op_rev
SELECT projects_overview.*
FROM projects_overview AS po
INNER JOIN customer_data ON po.cust_id = customer_data.cust_id
INNER JOIN faktura_saetze ON customer_data.faktura_satz_id = faktura_saetze.faktura_satz_id
WHERE faktura_op_rev LIKE 'bestimmter Text';
sollte es tun.
Gruss,
Vinzenz
Hallo Zusammen,
Zusammenfassung:
Alle Spalten aus projects_overview
Bedingung: Bestimmter Wert in faktura_saetze.faktura_op_revSELECT projects_overview.*
FROM projects_overview AS po
INNER JOIN customer_data ON po.p_cust_id = customer_data.cust_id
INNER JOIN faktura_saetze ON customer_data.faktura_satz_id = faktura_saetze.faktura_satz_id
WHERE faktura_op_rev LIKE 'bestimmter Text';sollte es tun.
Bewirkt genau gar nichts. Leider. BTW: Einen Inner Join brauche ich doch nur, wenn in der rechten Tabelle leere Felder vorkommen (können) - da genau das aber hier nicht der Fall ist, ist Inner Join hier doch eh obsolet, oder?
Moin!
Bewirkt genau gar nichts. Leider. BTW: Einen Inner Join brauche ich doch nur, wenn in der rechten Tabelle leere Felder vorkommen (können) - da genau das aber hier nicht der Fall ist, ist Inner Join hier doch eh obsolet, oder?
Wenn du die erste Tabelle komplett haben willst, und nur teilweise Elemente aus der zweiten Tabelle zuordnen kannst, brauchst du einen Outer Join.
Ein Inner Join ist im Prinzip der ganz normale Join (wenn ich richtig informiert bin).
Wenn deine Abfrage nicht funktioniert: phpMyAdmin (oder ähnliches) installieren und die Abfrage Stück für Stück testen. Also erst die eine Tabelle, dann die zweite joinen, dann die dritte joinen, dann mit WHERE selektieren. Dabei siehst du, wo es klemmt. Vielleicht sind deine Datenbankdaten nicht so, wie du denkst. Vielleicht ist der Join nicht so, wie du denkst. Durch schrittweises Zerlegen kommst du sicher weiter.
- Sven Rautenberg
Hallo Andreas,
Bewirkt genau gar nichts. Leider. BTW: Einen Inner Join brauche ich doch nur, wenn in der rechten Tabelle leere Felder vorkommen (können) - da genau das aber hier nicht der Fall ist, ist Inner Join hier doch eh obsolet, oder?
Ja und nein.
Ein Inner Join verknüpft zwei Tabellen über je eine Spalte jeder Tabelle und kann typischerweise auch mit einer analogen WHERE-Klausel dargestellt werden.
Inner Join bedeutet, dass im Ergebnis der Tabelle nur solche Datensätze stehen, bei denen die Werte der Join-Spalten in beiden Tabellen gleich sind.
Es gibt noch diverse andere Joins, den LEFT JOIN, den RIGHT JOIN, den (meist unerwünschten) CROSS JOIN, den THETA JOIN, ...
Ich bevorzuge die Schreibweise mit dem Join, weil sie den logischen Zusammenhang der einzelnen Tabellen klarer herausstellt als eine komplexe WHERE-Klausel.
Gruss,
Vinzenz
Hallo,
SELECT po.* FROM projects_overview AS po, customer_data AS cd, faktura_saetze AS fs WHERE (('1041375600' <= unix_timestamp(po.p_end) AND '1072825200' >= unix_timestamp(po.p_end)) OR ('1041375600' <= unix_timestamp(po.p_start) AND '1072825200' >= unix_timestamp(po.p_start)) OR ('1041375600' <= unix_timestamp(po.p_start) AND '1072825200' <= unix_timestamp(po.p_end))) AND cd.cust_id = po.p_cust_id AND fs.faktura_satz_id = cd.faktura_satz_id AND fs.faktura_op_rev LIKE 'Ext. Erlöse'
Ich verstehe nicht, wie man sinnvoll Abfragen schreiben kann, die in so einer Wurst hingeschrieben sind. Bitte beginne erstmals damit die Abfragen besser zu formatieren, um die Leserlichkeit zu erhöhen. [1]
Dann macht es imho auch Sinn, die WHERE-Klausel so zu schreiben, daß zuerst die Join-Bedingungen stehen[2] und dann erst die eigentlichen einschränkenden Kriterien.
Beispiel:
SELECT po.*
FROM projects_overview AS po,
customer_data AS cd,
faktura_saetze AS fs
WHERE cd.cust_id = po.p_cust_id
AND fs.faktura_satz_id = cd.faktura_satz_id
AND fs.faktura_op_rev LIKE 'Ext. Erlöse'
AND (('1041375600' <= unix_timestamp(po.p_end) AND '1072825200' >= unix_timestamp(po.p_end))
OR ('1041375600' <= unix_timestamp(po.p_start) AND '1072825200' >= unix_timestamp(po.p_start))
OR ('1041375600' <= unix_timestamp(po.p_start) AND '1072825200' <= unix_timestamp(po.p_end)))
Wo ist der Fehler?
Versuche es erstmals ohne den einschränkenden Bedingungen, damit Du siehst, ob die Joins richtig arbeiten.
Dann erst füge die Einschränkungen dazu.
Ich könnte mir beispielsweise vorstellen, daß es Probleme bei dem 'Ext. Erlöse' gibt und zwar wegen des Umlautes oder wegen der Groß-Klein-Schreibung. Abegesehen davon ist LIKE in diesem Falle unnötig, da Du ja nach exakt diesem text suchen willst.
Dann sieht es mir so aus, als ob faktura_op_rev prädestiniert für den Einsatz einer Schlüsseltabelle wäre, mit einer Integer-ID und einem beschreibenden Text.
Außerdem finde ich die zeitliche Einschränkung ungeschickt.
Zum einen diese unhandliche Formulierung über unix_timestamp-Konstanten. Ich denke daß muß leserlicher gehen (beispielsweise mit "unix_timestamp('1.1.2003') <= unix_timestamp(po.p_start)", aber da wird die DBMS-Dokumenattion sicherlich mehr dazu wissen.)
Und dann verstehe ich die Logik dahinter nicht. Es schein ja so zu sein, daß entweder p_start oder p_end im Zeitfenster liegen muß.
Wenn ich jetzt nochmals postuliere, daß p_start vor p_end sein muß, frage ich mich wozu dann die dritte Bedingung gut sein soll. Naja, das ist, so, wie ich es sehe, maximal noch ein Performance-Problem.
Grüße
Klaus
[1] Das Problem habe anscheinend viele Anwender, da man beispielsweise in diesem Forum sehr oft solche Moloche sieht.
[2] Sofern man nicht, wenn möglich, JOIN-Klauseln verwendet, die in den meisten Datenbankensystemen, die diese unterstützen, die Performance besser ist.