mySQL: join

Adrian der Grosse

Aktives Mitglied
Hallo zusammen,

Ich habe 3 Tabellen:
TabelleA
TabelleB: Bindeglied zwischen TabelleA und TabelleC
TabelleC

Zu jedem TabelleA-Datensatz können mehere TabelleC-Datensätze gehören.
Ein TabelleC Datensatz kann aber auch zu mehrere TabelleA-Datensätze gehören

Nun mein Vorhaben:
Select tabelleA.spalteX, (...) from TabelleA join TabelleB on TabelleB.tabA = TabelleA.id join TabelleC on TabelleC.id = TabelleB.tabC where TabelleC.wert = 'beispiel'

In TabelleC existierten mehrere Datensätze mit der Spalte wert = 'beispiel'.

Das Problem ist nun, dass bei einer Abfrage, einige Datensätze (TabelleA) mehrmals zurückgegeben werden. Ein distinct geht sehr zu lasten der Performance-> möchte ich nicht.

Ich denke mal man muss irgendwas an den Join's ändern, nur weiss ich nicht genau was, habe mir vorher damit gleich den mySQL-Server zerschossen
sad.gif


Hat jemand einen Tipp?

Vielen Dank
Adrian
 
Ich verwende zwar mySql nicht, habe insofern keine Erfahrung, ob es da spezielle Probleme mit Distinct gibt. Aber richtig vorstellen kann ich es mir nicht, sofern die Grundregeln beachtet sind:

- Alle drei Tabellen mit einspaltigem Primärschlüssel (Integer), auch die Verknüpfungstabelle B.
- Die Fremdschlüsselspalten in B sollten indiziert sein.

Der Join sieht zwar insofern komisch aus, weil ich das konsistent schreibe:

SQL Select tabelleA.spalteX, (...)
from TabelleA Inner join TabelleB
on TabelleA.id = TabelleB.tabA Inner Join TabelleC
on TabelleB.tabC = TabelleC.id
where TabelleC.wert = 'beispiel'


aber ein Optimierer müßte damit auch klarkommen.

Zur Not könnte man natürlich, falls die mySql-Version Unterabfragen unterstützt, auch das nutzen:


SQL Select A.spalte X
From tabelleA As A
Where A.id In (Select B.tabA
From tabelleB As B
Where B.tabC In (Select C.Id From tabelleC As C Where C.wert = 'beispiel')
)


Aber eigentlich sollten beide Varianten gleich schnell sein.
 
@jAuer: Leider bringt dein Tipp nichts
sad.gif


CODE
TabelleA
id SpalteA SpalteB
------------------------
1 haus sql
2 ayom netz
3 inter net
4 blub blub
5 fisch jäger

TabelleB
tabA tabC
------------------------
2 1
2 3


TabelleC
id wert name
------------------------
1 a cool
2 b uncool
3 a extrem
4 a mega
5 e neee
6 f nix



SQL-Abfrage:

SQL Select TabelleA.id, TabelleA.SpalteA, TabelleA.SpalteB from TabelleA join TabelleB on TabelleB.tabA = TabelleA.id join TabelleC on TabelleC.id = TabelleB.tabC Where tabelleC.wert = 'A';



Gibt aus:

CODE
id SpalteA SpalteB
2 ayom netz
2 ayom netz



Was ich gerne hätte:

CODE
id SpalteA SpalteB
2 ayom netz



SQL-Aufbau:

SQL CREATE TABLE `tabellea` (
`id` int(10) unsigned NOT NULL auto_increment,
`SpalteA` varchar(10) NOT NULL default '',
`SpalteB` varchar(10) NOT NULL default '',
PRIMARY KEY (`id`)
) TYPE=MyISAM AUTO_INCREMENT=6;


INSERT INTO `tabellea` VALUES (1, 'haus', 'sql');
INSERT INTO `tabellea` VALUES (2, 'ayom', 'netz');
INSERT INTO `tabellea` VALUES (3, 'inter', 'net');
INSERT INTO `tabellea` VALUES (4, 'blub', 'blub');
INSERT INTO `tabellea` VALUES (5, 'fisch', 'jäger');


CREATE TABLE `tabelleb` (
`tabA` int(10) unsigned NOT NULL default '0',
`tabC` int(10) unsigned NOT NULL default '0'
) TYPE=MyISAM;



INSERT INTO `tabelleb` VALUES (2, 1);
INSERT INTO `tabelleb` VALUES (2, 3);



CREATE TABLE `tabellec` (
`id` int(10) unsigned NOT NULL auto_increment,
`wert` char(1) NOT NULL default '',
`name` varchar(10) NOT NULL default '',
PRIMARY KEY (`id`),
KEY `wert` (`wert`)
) TYPE=MyISAM AUTO_INCREMENT=7;


INSERT INTO `tabellec` VALUES (1, 'a', 'cool');
INSERT INTO `tabellec` VALUES (2, 'b', 'uncool');
INSERT INTO `tabellec` VALUES (3, 'a', 'extrem');
INSERT INTO `tabellec` VALUES (4, 'a', 'mega');
INSERT INTO `tabellec` VALUES (5, 'e', 'nee');
INSERT INTO `tabellec` VALUES (6, 'f', 'nix');

 
Aber es ist völlig logisch, daß Du bei einer m:n - Beziehung im Zweifelsfall mehrere Ergebnisse bzw. Ergebniswiederholungen erhälst. Das ist einfach eine Folge der Datenstruktur.

Sprich: Entweder klappt das mit den Unterabfragen (nicht bei älteren mySql) oder Du mußt Distinct nutzen und mit der Performance leben.

Abgesehen davon hast Du in der entscheidenden Tabelle B keinen Primärschlüssel. Das braucht dann natürlich lange.
 
mach ein group auf die felder, die zurückgegeben werden, also:
group by id,SpalteA,SpalteB
 
QUOTE (HoBbY @ Di 21.11.2006, 21:09)Gibt aus:

CODE
id SpalteA SpalteB
2 ayom netz
2 ayom netz



Was ich gerne hätte:

CODE
id SpalteA SpalteB
2 ayom netz





Das ist mal schick, mit den Creates und Inserts kann man doch fröhlich ausprobieren ;-)

Mir ist noch nicht ganz klar was Du eigentlich willst. Weil wenn Du nur die ID und noch zwei Felder aus TabelleA willst, dann brauchst Du überhaupt keinen Join zum B und zum C. Ohne diesen Join fallen dann auch alle Duplikate weg.

Wenn Du aber auch Daten aus TabelleC willst, dann musst Du nen Join machen. Und weil die Relation A zu C eine m:n-Relation ist, kriegst Du auch Duplikate entweder beim A oder beim C (resp. von beidem, je nach vorhandenen Daten). Das lässt sich nicht verhindern, ausser Du holst zwei separate Resultsets und stellst die dann in der Seite entsprechend dar.

Griessli
Irene
 
ich habe es so verstanden, dass er Duplikate raus haben will.
Group müsste da funktionieren, und bessere Performance haben als Distinct.
 
Aus meiner Sicht nützt ein Group da auch nichts. Die Felder, deren Werte man sehen will, müssen im "group by" sein, womit wieder Duplikate drin sind. Bei nem Group müssen alle Felder, die nicht Teil des "group by" sind, irgendwie aggregiert werden (Summe, Mittelwert, Grösstes oder Kleinstes, irgendwas halt), und das macht im Normalfall nur bei Zahlenwerten Sinn. Mit

SQL Select tabelleA.spaltea, tabellea.spalteb, tabellec.wert, tabellec.name
from TabelleA join TabelleB on TabelleB.tabA = TabelleA.id join TabelleC on TabelleC.id = TabelleB.tabC
group by tabelleA.spaltea, tabellea.spalteb, tabellec.wert, tabellec.name

hab ich wieder Duplikate drin. Allerdings benutze ich nicht MySQL, aber ich nehme mal an, dass MySQL die SQL-Standards genauso anwendet wie alle anderen Datenbanken.

Griessli
Irene
 
es sind ja alle Felder im Group By - es werden keine Felder aggregiert

er will ja nur id, spalteA, spalteB im resultset.

in seiner Abfrage am Anfang des Threads fehlt nur ein Group:



also:

SQL Select TabelleA.id, TabelleA.SpalteA, TabelleA.SpalteB
from TabelleA join TabelleB on TabelleB.tabA = TabelleA.id join TabelleC on TabelleC.id = TabelleB.tabC
Where tabelleC.wert = 'A'
Group By TabelleA.id, TabelleA.SpalteA, TabelleA.SpalteB



Wenn man ins Select noch ein count(*) hinzufügt, zählt es sogar die Duplikate.
 
Zurück
Oben