SQL: Kann man jede IN-Klausel in einen JOIN umwandeln?
-
Habe gerade folgendes Problem (stark vereinfacht):
Ein Object hat mehrere Labels.
Ein Label kann aber auch zu mehreren Objects gehören.
Klare :-Beziehung, Zwischentabelle nennen wir hier mal ObjectLabels.Ich suche nun alle Objects die sowohl das Label A als auch das Label B haben.
Derzeitige Lösung mit IN-Klasuel:
SELECT * FROM Object o WHERE o.o_id IN ( SELECT ol.o_id FROM ObjectLabels ol INNER JOIN Labels l ON ol.l_id = l.l_id WHERE l.l_label = 'A' OR l.l_label = 'B' )
Kann man das auch ohne Subselect/IN-Klausel lösen?
MfG SideWinder
-
Ohne Sub-Select geht's glaub ich nur mit "DISTINCT *", und das ist bäh.
(Ohne DISTINCT * hättest du sonst Duplikate, wenn Objekte Label "A" und "B" haben)Ohne IN, aber immer noch mit Sub-Select geht's natürlich:
SELECT * FROM ( SELECT DISTINCT ol.o_id FROM ObjectLabels ol INNER JOIN Labels l ON ol.l_id = l.l_id WHERE l.l_label = 'A' OR l.l_label = 'B' ) AS ids INNER JOIN Object o ON o.o_id = ids.o_id
Nur... wieso willst du überhaupt das "IN" loswerden?
Ich hätte die Query vermutlich so geschrieben:SELECT * FROM Object WHERE o_id IN ( SELECT DISTINCT o_id FROM ObjectLabels WHERE l_id IN ( SELECT l_id FROM Labels WHERE l_label IN ('A', 'B') ) )
DISTINCT wäre hier nicht nötig, aber ich finde es "logischer" wenn das Sub-Select für IN() keine Duplikate liefert.
Ich weiss natürlich nicht mit welchem DBMS du arbeitest, aber MS-SQL Server kann IN ziemlich gut optimieren. Der Query-Plan ist bei IN vs. JOIN auch oft der selbe (und damit auch die Performance oft gleich). Von daher nehme ich lieber das was sich besser lesen lässt bzw. für mich "logischer" ist.
-
p.S.:
Ich suche nun alle Objects die sowohl das Label A als auch das Label B haben.
Nö.
Deine Abfrage sucht Objekte die entweder das Label A oder das Label B oder beide Labels haben.Wenn du nur Objekte haben willste die beide Labels haben musst du was anderes machen. Gibt da natürlich auch wieder mehrere Möglichkeiten. Über 2x IN oder 2x EXISTS oder HAVING COUNT(*) = 2 ...
-
Danke für die Informationen, dann belasse ich es bei der IN-Klausel. Leider nur HSQLDB als DB...geht mir mehr ums Theoretische als ums Performante
Ich habe oben einen Fehler eingebaut, dort sollte eigentlich AND stehen.
MfG SideWinder
-
Wenn dort AND steht bekommst du gar keine Resultate
-
Hast recht. D.h. sobald ich alle Objects haben will die *alle* Labels haben bleibt mir gar nichts anderes übrig als mit GROUP BY und HAVING count(*) = anzahl_der_geforderten_labels zu arbeiten?
Eieiei.
MfG SideWinder
-
Das wird aber One-Hell-Of-A-Dirty-SQL-String-Builder
MfG SideWinder
-
Hm. Stell ich mir jetzt nicht SO wild vor.
Schreib mal den SQL Code den du generieren willst, vielleicht machst du ja irgendwas komplizierter als nötig
-
hustbaer schrieb:
Hm. Stell ich mir jetzt nicht SO wild vor.
Schreib mal den SQL Code den du generieren willst, vielleicht machst du ja irgendwas komplizierter als nötigFolder (hat 0:* Objects) Object (hat 0:* Infos, gehört zu genau einem Folder) Info (gehört zu genau einem Object) Label (*:* mit Objects)
Suche nach Objects mit verschiedensten, generischen Klauseln die entweder alle AND oder alles OR verknüpft werden:
Folder.title ** Object.[attr] * Info.type = ? && Info.value = ? *** Label.name = ? *** * ... einfache WHERE-Klausel ** ... einfache WHERE-Klausel, Join dazubasteln *** ... über IN + GROUP BY + HAVING count(*) == anz_infos bei AND oder > 0 bei OR
Übersehe ich etwas?
MfG SideWinder
-
Hmmm.
OK.
Das wird dann insgesamt relativ wild. Der "muss Labels X, Y, Z haben" Teil selbst sollte aber halbwegs überschaubar bleiben.