2009-03-04 17 views
2

Danke für die tollen Antworten!Auswählen mit Unterabfragen in MySQL (Unterabfragen mit ANY und IN)

Weitere Informationen


Das ist schwer zu erklären, lässt die Bühne so eingestellt ...

userActions   userGroupMap 
+------+--------+ +------+-------+ 
| user | action | | user | group | 
+------+--------+ +------+-------+ 
| x | acted! | | x | a  | 
| y | acted! | | y | a  | 
| y | acted! | | z | b  | 
| z | acted! | +------+-------+ 
| y | acted! | 
| z | acted! | 
| x | acted! | 
| z | acted! | 
+------+--------+ 

Ich möchte die Aktionen der Gruppe a auswählen. Meine Idee war zu

SELECT actions, user FROM userActions 
    WHERE user = (SELECT user, group FROM userGroupMap WHERE group = a) 

Aber offensichtlich diese Unterabfrage gibt mehr als eine Zeile zurück. Sollte ich ein JOIN verwenden?

Subquery returns more than 1 row 

Antwort

3

Ein Ansatz hierfür ist:

SELECT actions, 
     user 
FROM userActions 
WHERE user IN 
       (SELECT user 
       FROM userGroupMap 
       WHERE [group] = 'a' 
       ); 

jedoch mit großen Tabellen, diese Abfrage ineffizient zu sein scheint und eine Verknüpfung zu tun ist besser:

SELECT actions, 
     userActions.user 
FROM userActions 
     INNER JOIN 
       (SELECT user 
       FROM userGroupMap 
       WHERE [group] = 'a' 
      ) AS tmp 
     ON  userActions.user = tmp.user; 

Alternativ kann, wie Jonathon erwähnt, Sie könnten dies getan haben, und es ist so effizient, wenn nicht mehr:

SELECT actions, 
     userActions.user 
FROM userActions 
     INNER JOIN userGroupMap 
     ON  userActions.user = userGroupMap.user 
WHERE [group] = 'a'; 
+0

Danke! Mit deiner Antwort habe ich meine Ergebnisse fehlerfrei bekommen. Ich schätze auch den Hinweis auf große Tische (weshalb ich Ihre Antwort akzeptiert habe). Können Sie näher erläutern, warum Sie die Gruppe in Klammern setzen - "[group]"? – Blaine

+0

Es gibt keinen ersichtlichen Grund, warum dies eine Unterabfrage erfordert; ein gerader innerer Join mit der Filter WHERE-Klausel sollte ebenfalls die Aufgabe erfüllen. –

+0

@Blaine: Ich lege [group] in Klammern, weil ein Schlüsselwort und einige DBMS ausflippen, wenn Schlüsselwörter als Spalten-/Tabellennamen nicht explizit angegeben sind. Der gleiche Grund, den ich [Tabelle] in Klammern gesetzt habe. @ Jonathan Leffler: Sie haben Recht, ich denke, ich war nur abgelenkt von der Frage und es mit Unterabfragen. – achinda99

0
SELECT actions, user FROM userActions 
    WHERE user = (SELECT user FROM userGroupMap WHERE group = a) 

Die Unterabfrage zurückkehrt Benutzer- und Gruppen (zwei Felder), wenn es nur Benutzer zurückkehren sollte.

+0

Ich stimme zu, dass die Unterabfrage teilweise wegen der mehreren Spalten falsch war; Bei der Frage ging es jedoch um die Rückgabe von mehr als einer Zeile, und Ihre Version tut dies immer noch - und scheitert daher zur Laufzeit. –

1
SELECT actions, user FROM userActions 
    WHERE user IN (SELECT user FROM userGroupMap WHERE group = a) 

SELECT actions, user FROM userActions 
    WHERE user = ANY (SELECT user FROM userGroupMap WHERE group = a) 

(Geändert:. Nur der Benutzer Spalte zurückgegeben werden soll, wie andere schon angemerkt)

1

kann nicht einfach so etwas wie:

SELECT 
    a.actions, 
    a.user 
FROM 
    userActions a 
    INNER JOIN userGroupMap g 
    ON a.user = g.user 
WHERE 
    g.group = 'a' 
+0

Ja; Das funktioniert in dieser Situation am besten. Aber es gibt auch das Problem, wie man mit Unterabfragen arbeitet, die mehrere Zeilen zurückgeben, und zwar mit IN oder = ANY oder Varianten davon. Diese Abfragen können jedoch oft mit einer Verknüpfung anstelle einer Unterabfrage neu geschrieben werden. –

1

Eigentlich diese Abfrage geben was Sie benötigen Sie:

SELECT actions, user 
FROM userActions 
WHERE user IN 
    (SELECT user FROM userGroupMap WHERE group = 'a') 
0

Anstatt Unterabfrage beitreten verwenden:

SELECT 
    userActions.action, 
    userActions.user 
FROM 
    userActions 
CROSS JOIN userGroupMap ON 
    userGroupMap.user = userActions.user AND 
    userGroupMap.group = 'a' 
+0

Bei großen Tabellen wird dadurch die Größe der temporären Tabelle drastisch erhöht, bevor sie mit der Gruppe reduziert wird. Es ist weniger effizient als die Teilnahme an einer Teilmenge von Daten. – achinda99

+0

Was, wenn wo in Verbindung gesetzt? Wird das besser sein? –

+0

Keine Notwendigkeit für CROSS JOIN; benutze INNER JOIN (oder einfach JOIN). –