2010-07-07 5 views
8

J'ai un groupe d'utilisateurs, dont chacun a beaucoup de messages. Schéma:requête SQL au moins un de quelque chose

Users: id 
Posts: user_id, rating 

Comment puis-je trouver tous les utilisateurs qui ont au moins un poste avec une note ci-dessus, disons, 10?

Je ne suis pas sûr si je devrais utiliser une sous-requête pour cela, ou s'il y a un moyen plus facile.

Merci!

Répondre

19

Pour trouver tous les utilisateurs avec au moins un poste avec une note supérieure à 10, utilisez:

SELECT u.* 
    FROM USERS u 
WHERE EXISTS(SELECT NULL 
       FROM POSTS p 
       WHERE p.user_id = u.id 
       AND p.rating > 10) 

EXISTE ne se soucie pas de l'instruction SELECT dans les il - vous pourriez remplacer NULL par 1/0, ce qui devrait entraîner une erreur mathématique pour diviser par zéro ... Mais ce ne sera pas le cas, car EXISTS ne concerne que le filtrage dans la clause WHERE. La corrélation (le WHERE p.user_id = u.id) explique pourquoi cette sous-requête est corrélée et ne retournera que les lignes de la table USERS où les valeurs id correspondent, en plus de la comparaison de notation. EXISTS est également plus rapide, selon la situation, car il retourne vrai dès que le critère est satisfait - les doublons n'ont pas d'importance.

+0

Pouvez-vous m'expliquer cela. La requête interne va recevoir n'importe quel nombre de lignes NULL. Alors, EXISTS le résume en vrai ou faux, donc ne va-t-il pas obtenir tous les utilisateurs, ou aucun? – ash

+1

@Jasie: EXISTS ne se soucie pas de l'instruction SELECT en son sein - vous pourriez remplacer NULL par 1/0, ce qui devrait entraîner une erreur mathématique pour la division par zéro ... Mais ce ne sera pas le cas, car EXISTS ne concerne que avec le filtrage dans la clause WHERE. La corrélation (le 'WHERE p.user_id = u.id') est pourquoi on appelle cela une sous-requête corrélée, et retournera seulement les lignes de la table USERS où les valeurs d'id correspondent, en plus de la comparaison de notation. –

+0

@Jasie: EXISTS est également plus rapide, selon la situation, car il retourne vrai dès que les critères sont remplis - les doublons n'ont pas d'importance. –

1

Utilisez une jointure:

SELECT * from users INNER JOIN posts p on users.id = p.user_id where p.rating > 10; 
+1

Cela retournera les doublons si les utilisateurs ont plus d'un message avec une note supérieure à 10. Ajouter 'DISTINCT', ou voir ma requête pour une alternative. –

+0

Si vous voulez juste une liste d'utilisateurs, utilisez ce qui précède mais remplacez * par des utilisateurs distincts.id – Kendrick

2

Vous pouvez joindre les tables pour trouver les utilisateurs concernés et utiliser DISTINCT afin que chaque utilisateur est dans le jeu de résultats au plus une fois, même si elles ont plusieurs postes avec> Note 10:

select distinct u.id,u.username 
from users u inner join posts p on u.id = p.user_id 
where p.rating > 10 
0
SELECT max(p.rating), u.id 
    from users u 
INNER JOIN posts p on users.id = p.user_id 
where p.rating > 10 
group by u.id; 

De plus, cela vous dira quelle est leur meilleure note.

+0

Désolé - reformaté pour arrêter le défilement. Plus facile à lire, plus facile à voter. –

+0

Merci, ça a l'air mieux comme ça. – Zak

0

La bonne réponse à votre question est la réponse d'OMG Ponies: WHERE EXISTS est plus descriptif et presque toujours plus rapide. Mais "SELECT NULL" a l'air vraiment moche et contre-intuitif pour moi. J'ai vu SELECT * ou SELECT 1 comme une meilleure pratique pour cela.

Une autre façon, dans le cas où nous recueillons des réponses:

SELECT u.id 
FROM users u 
    JOIN posts p on u.id = p.user_id 
WHERE p.rating > 10 
GROUP BY u.id 
HAVING COUNT(*) > 1 

Cela pourrait être utile si ce n'est pas toujours 1 que vous testez sur.

1
select distinct id 
from users, posts 
where id = user_id and rating > 10 
Questions connexes