2008-09-01 9 views
6

Je voudrais trouver les différentes façons de résoudre un problème de la vie réelle que j'avais: imaginez-vous avoir un concours, ou un jeu, au cours duquel les utilisateurs collectent points. Vous devez créer une requête pour afficher la liste des utilisateurs ayant les meilleurs scores "n". Je fais un exemple pour clarifier. Disons que c'est la table des utilisateurs, avec les points gagnés:Requête SQL pour obtenir les meilleurs scores "n" d'une liste

UserId - Points 
1  - 100 
2  - 75 
3  - 50 
4  - 50 
5  - 50 
6  - 25 

Si je veux que les 3 meilleurs scores, le résultat sera:

UserId - Points 
1  - 100 
2  - 75 
3  - 50 
4  - 50 
5  - 50 

Cela peut être réalisé en une vue ou un procédure stockée, comme vous le souhaitez. Mon cible db est Sql Server. En fait, j'ai résolu cela, mais je pense qu'il existe différentes façons d'obtenir le résultat ... plus rapide ou plus efficace que le mien.

Répondre

9

Untested, mais devrait fonctionner:

select * from users where points in 
(select distinct top 3 points from users order by points desc) 
1

@bosnic, je ne pense pas que cela fonctionnera comme l'a demandé, je ne suis pas familier avec MS SQL mais j'attendre pour revenir seulement 3 rangs et ignorez le fait que 3 utilisateurs sont à égalité pour la 3ème place.

Quelque chose comme cela devrait fonctionner:

select userid, points 
    from scores 
    where points in (select top 3 points 
         from scores 
         order by points desc) 
    order by points desc 
0

@Espo merci pour la vérification de la réalité - a ajouté le sous-sélection pour corriger cela.

Je pense que la réponse la plus simple est de:

select userid, points from users 
where points in (select distinct top N points from users order by points desc) 

Si vous voulez le mettre dans une procédure stockée qui prend N comme paramètre, alors vous devez soit faire lire le SQL dans une variable puis l'exécuter, ou faire le nombre de lignes trick:

declare @SQL nvarchar(2000) 
set @SQL = "select userID, points from users " 
set @SQL = @SQL + " where points in (select distinct top " + @N 
set @SQL = @SQL + " points from users order by points desc)" 

execute @SQL 

ou

SELECT UserID, Points 
FROM  (SELECT ROW_NUMBER() OVER (ORDER BY points DESC) 
     AS Row, UserID, Points FROM Users) 
     AS usersWithPoints 
WHERE Row between 0 and @N 

Les deux exemples supposent SQL Server et n'ont pas été testés.

0

@ Rob # 37760:

select top N points from users order by points desc 

Cette requête ne sélectionnera 3 lignes si N est 3, voir la question. "Top 3" devrait retourner 5 lignes.

1

Que diriez-vous:

select top 3 with ties points 
from scores 
order by points desc 

Je ne sais pas si "avec des liens" fonctionne sur tout autre SQL Server.

Sur SQL Server 2005 et, vous pouvez passer le nombre « top » comme paramètre int:

select top (@n) with ties points 
from scores 
order by points desc 
4

est ici un qui fonctionne - Je ne sais pas s'il est plus efficace, et il est SQL Server 2005+

with scores as (
    select 1 userid, 100 points 
    union select 2, 75 
    union select 3, 50 
    union select 4, 50 
    union select 5, 50 
    union select 6, 25 
), 
results as (
    select userid, points, RANK() over (order by points desc) as ranking 
    from scores 
) 
select userid, points, ranking 
from results 
where ranking <= 3 

Il est évident que le premier « avec » est de mettre en place les valeurs, de sorte que vous pouvez tester la seconde avec, et dernier travail de sélection - vous pourriez commencer à « avec les résultats ... » si vous étiez interroger par rapport à une table existante.

+0

J'ai un problème similaire et essayait d'utiliser MAX, puis j'ai lu votre répondre et mémorisé DENSE_RANK. M'a sauvé beaucoup de temps. – DataGirl

0

Hamilton @ Matt

Votre réponse fonctionne avec l'exemple ci-dessus, mais ne fonctionne pas si l'ensemble de données était de 100, 75, 75, 50, 50 (où il retournerait seulement 3 lignes). TOP WITH TIES ne comprend que les liens de la dernière ligne retournée ...

0

Creuset l'a obtenu (en supposant que SQL 2005 est une option).

0

En fait, une modification du WHERE IN, en utilisant un INNER JOIN sera beaucoup plus rapide.

SELECT 
    userid, points 
FROM users u 
INNER JOIN 
(
    SELECT DISTINCT TOP N 
     points 
    FROM users 
    ORDER BY points DESC 
) AS p ON p.points = u.points 
0

essayer cette

select top N points from users order by points desc 
0

Hey je trouve toutes les autres réponses peu long et inefficace Ma réponse serait:

select * from users order by points desc limit 0,5

cela rendra top 5 points