2009-03-04 6 views
2

Merci pour les bonnes réponses!Sélection avec des sous-requêtes dans MySQL (Sous-requêtes avec ANY, et IN)

Pour plus d'informations


Il est difficile d'expliquer, donc permet de définir la scène ...

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! | 
+------+--------+ 

Je souhaite sélectionner les actions du groupe a. Mon idée était de

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

Mais évidemment, cette sous-requête renvoie plus d'une ligne. Devrais-je utiliser un JOIN?

Subquery returns more than 1 row 

Répondre

3

Une approche est la suivante:

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

Cependant, avec de grandes tables, cette requête tend à être inefficace et de faire une jointure est mieux:

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

Sinon, comme Jonathon mentionné, vous auriez pu faire cela et c'est à peu près aussi efficace, sinon plus:

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

Merci! Avec votre réponse j'ai obtenu mes résultats sans faille. J'apprécie également la note sur les grandes tables (c'est pourquoi j'ai accepté votre réponse). Pouvez-vous expliquer pourquoi vous avez mis le groupe entre parenthèses - "[groupe]"? – Blaine

+0

Il n'y a aucune raison évidente pour laquelle cela nécessite une sous-requête; une jointure interne droite avec la clause WHERE de filtrage devrait également faire le travail. –

+0

@Blaine: Je mets [group] entre parenthèses car son mot-clé et certains SGBD flippent si les mots-clés utilisés comme noms de colonne/table ne sont pas explicitement indiqués. La même raison que je mettrais [table] entre parenthèses. @Jonathan Leffler: Vous avez raison, je pense que j'étais juste distrait par la question et l'utilisation de sous-requêtes. – achinda99

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

Le sous-requête a été utilisateur RESTITUTIOIN groupe (deux champs) quand il devrait être de retour juste utilisateur.

+0

Je suis d'accord que la sous-requête était erronée en partie à cause des multiples colonnes; cependant, la question était de renvoyer plus d'une ligne, et votre version le fait toujours - et échoue donc à l'exécution. –

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) 

(modifiée:. Seule la colonne utilisateur doit être retourné, comme indiqué par d'autres)

1

Ne pourriez-vous faire quelque chose comme:

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

Oui; cela fonctionne le mieux dans cette situation. Mais il y a aussi le problème de 'comment traiter les sous-requêtes qui retournent plusieurs lignes', et cela se fait avec IN ou = ANY ou des variantes de celles-ci. Mais ces requêtes peuvent souvent être réécrites avec une jointure au lieu d'une sous-requête. –

1

En fait, cette requête donnera vous ce que vous avez besoin:

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

utiliser plutôt que se joindre à sous-requête:

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

Sur les grandes tables, cela augmentera considérablement la taille de la table temporaire avant de l'abattre en groupe. C'est moins efficace que de se joindre à un sous-ensemble de données. – achinda99

+0

Que faire si mis où statment dans la jointure? Est-ce que ce sera mieux? –

+0

Pas besoin de CROSS JOIN; utilisez INNER JOIN (ou simplement JOIN). –

Questions connexes