SELECT mit WHERE ueber meherer rows

Hi,

zwei Spalten:
S1 S2
a x
a y
b y
b z
c x
c z

Ich haette gerne alle Elemente aus S1 zurueck, fuer die in S2 ein x und ein y steht. Im Beispiel also ein a. Und das braeuchte ich auch noch so, dass es bequem erweiterbar auf mehr Werte, also alle aus S1, in denen in S2 ein x, y und z steht. (Waere im Beispiel freilich leer.) Jemand Ideen?

Danke im Voraus,
Gruss vom Frank.

Moin,

keine Idee - nur ne Lösung ;o))

select *
from tab a, tab b, tab c
where a.s1 = b.s1 and b.s1 = c.s1 and b.s2 = ‚x‘ and c.s2 = ‚y‘

Vielleicht nciht das eleganteste, aber funktionieren sollte es ;o)

Gruß
Bernd

keine Idee - nur ne Lösung ;o))

select *
from tab a, tab b, tab c
where a.s1 = b.s1 and b.s1 = c.s1 and b.s2 = ‚x‘ and c.s2 =
‚y‘

Ah, cool, funktioniert wirklich. Scheinbar tut’s auch ein

SELECT a.s1
FROM tab AS a, tab AS b
WHERE a.s1 = b.s1 WHERE a.s2 = ‚x‘ AND b.s2 = ‚y‘

Oder macht das was anderes? Ergebnis sieht erstmal gut aus.

Dummerweise skaliert das, zumindest vom Schreibaufwand, nicht besonders gut fuer beliebige maechtige Mengen der Art {x,y}: pro Element gibt das ein weitere Tabelle im FROM und einen weiteren Vergleich im WHERE. Also mal fuer {w,x,y,z}:

SELECT a.S1
FROM tab AS a, tab AS b, tab AS c, tab AS d
WHERE a.S1=b.S1 AND a.S2=‚w‘ AND b.S2=‚x‘ AND c.S2=‚y‘ AND d.S2=‚z‘

Stimmt das? Oder macht das ganz was anderes? Hm… ich hab da irgendwie so Zweifel.

Danke,
Gruss vom Frank.

Hallo Frank,

Dummerweise skaliert das, zumindest vom Schreibaufwand, nicht
besonders gut fuer beliebige maechtige Mengen …

Nicht nur vom Schreibaufwand: Wenn Du kein Index anlegst rödeln Deine Platten bestimmt längere Zeit.

SELECT a.S1
FROM tab AS a, tab AS b, tab AS c, tab AS d
WHERE a.S1=b.S1 AND a.S2=‚w‘ AND b.S2=‚x‘ AND c.S2=‚y‘ AND
d.S2=‚z‘

Stimmt das? …

Nein!

SELECT a.S1
 FROM tab AS a, 
 tab AS b, 
 tab AS c, 
 tab AS d
 WHERE a.S1=b.S1
 and b.S1=c.S1
 and c.S1=d.S1
 AND a.S2='w' 
 AND b.S2='x' 
 AND c.S2='y' 
 AND d.S2='z'
;

MfG Georg V.

1 Like

Dummerweise skaliert das, zumindest vom Schreibaufwand, nicht
besonders gut fuer beliebige maechtige Mengen …

Nicht nur vom Schreibaufwand: Wenn Du kein Index anlegst
rödeln Deine Platten bestimmt längere Zeit.

Hm, das dachte ich. Bei 25k Datensaetzen laeuft das aber noch halbwegs flott. Gibt’s denn da trotzdem was effizienteres?

SELECT a.S1
FROM tab AS a,
tab AS b,
tab AS c,
tab AS d
WHERE a.S1=b.S1
and b.S1=c.S1
and c.S1=d.S1
AND a.S2=‚w‘
AND b.S2=‚x‘
AND c.S2=‚y‘
AND d.S2=‚z‘
;

Ah! Cool, danke. Wenn man das umstellt ergibt das fuer mehr Vergleiche ein huebsches Muster.

Gruss vom Frank.

Hi Frank,

ich behaupte mal das hier tut das gewünschte (jeweils gleich auch mit drei Kriterien, dann ist es denke ich leichter zu verstehen, wie man das erweitert):
2 Kriterien:

SELECT s1 
 FROM myTab 
 WHERE s2 = 'x' 
INTERSECT
SELECT s1 
 FROM myTab 
 WHERE s2 = 'y';

3 Kriterien:

SELECT s1 
 FROM myTab 
 WHERE s2 = 'x' 
INTERSECT
SELECT s1 
 FROM myTab 
 WHERE s2 = 'y'
INTERSECT
SELECT s1 
 FROM myTab 
 WHERE s2 = 'z';

Wenn die Paare (s1,s2) eindeutig sind geht auch der hier:

SELECT s1, COUNT(\*)
 FROM myTab 
 WHERE s2 IN ('x','y') 
 GROUP BY s1
 HAVING COUNT(\*) = 2;

bzw.

SELECT s1, COUNT(\*)
 FROM myTab 
 WHERE s2 IN ('x','y','z') 
 GROUP BY s1
 HAVING COUNT(\*) = 3;

und dann wäre da noch die Variante mit

SELECT s1 
 FROM myTab o
 WHERE s2 = 'x' 
 AND EXISTS (SELECT s1 
 FROM myTab i1 
 WHERE i1.s1 = o.s1 
 AND i1.s2 = 'y');

bzw.

SELECT s1 
 FROM myTab o
 WHERE s2 = 'x' 
 AND EXISTS (SELECT \*
 FROM myTab i1 
 WHERE i1.s1 = o.s1 
 AND i1.s2 = 'y')
 AND EXISTS (SELECT \*
 FROM myTab i2 
 WHERE i2.s1 = o.s1 
 AND i2.s2 = 'z');

Der bereits vorgeschlage Join ist natürlich auch eine Möglichkeit. Performancemässig würde ich auf den COUNT als schnellsten tippen, aber das kommt halt stark auf die Daten und das RDBMS an. Ausserdem geht der Count wie gesagt nur, wenn (s1,s2) ein eindeutiger Schlüssel ist (was du diesfalls auch gleich per CONSTRAINT festlegen solltest).

Alles übrigens ungetestet und ohne Gewehr.

Gruß
Martin

2 Kriterien:

SELECT s1
FROM myTab
WHERE s2 = ‚x‘
INTERSECT
SELECT s1
FROM myTab
WHERE s2 = ‚y‘;

Ich bin leider arm und hab nur eine MySQL. Die scheint kein INTERSECT zu koennen. Tatsaechlich ist das aber genau das, was ich machen will: Schnittmengen bilden. Haette ich ja mal googlen koennen…

Wenn die Paare (s1,s2) eindeutig

Ja, es gibt ein constraint unique (s1, s2).

sind geht auch der hier:

SELECT s1, COUNT(*)
FROM myTab
WHERE s2 IN (‚x‘,‚y‘)
GROUP BY s1
HAVING COUNT(*) = 2;

bzw.

SELECT s1, COUNT(*)
FROM myTab
WHERE s2 IN (‚x‘,‚y‘,‚z‘)
GROUP BY s1
HAVING COUNT(*) = 3;

Hm, das sieht ja eigentlich huebsch uebersichtlich aus und wuerde mir persoenlich sogar am besten gefallen. Allerdings stellt es sich gerade etwas bockig an, wenn ich es als subselect verwende und entgegen Deiner Vermutung braucht das aber tatsaechlich laenger als die andere vorgeschlagene Loesung (die dann wohl ein join ist). Weiterhin scheint es nicht zu funktionieren, wenn in der Vergleichsmenge doppelte Elemente vorhanden sind, also die Anfrage degeneriert zu „gib mir alle Elemente aus S1, fuer die in S2 x und x steht“, was der gesunde Menschenverstand (alternativ die Boolsche Algebra) natuerlich runterbricht auf „gib mir alle Elemente aus S1, fuer die in S2 x steht“, dieses SQL statement aber nicht, das join schon. Auf doppelte Elemente muss ich hier extern pruefen.

und dann wäre da noch die Variante mit

SELECT s1
FROM myTab o
WHERE s2 = ‚x‘
AND EXISTS (SELECT s1
FROM myTab i1
WHERE i1.s1 = o.s1
AND i1.s2 = ‚y‘);

bzw.

SELECT s1
FROM myTab o
WHERE s2 = ‚x‘
AND EXISTS (SELECT *
FROM myTab i1
WHERE i1.s1 = o.s1
AND i1.s2 = ‚y‘)
AND EXISTS (SELECT *
FROM myTab i2
WHERE i2.s1 = o.s1
AND i2.s2 = ‚z‘);

Hm, das schaut eigentlich auch nicht so schlecht aus. Tendenziell ist das aber aus Anwendungssicht auch nicht einfacher zu bauen als der join: ich muss einen Tabelleniterator mitschleppen, Listen mit Bedingungen erweitern, usw. Wesentlicher Unterschied duerfte sein, dass ich das andere schon fertig hab. :wink:

Trotzdem Danke, vielleicht muss ich das mal aus irgendwelchen Gruenden umstellen.

Gruss vom Frank.