2011-01-23 1 views
8

J'ai une sorte de demande impossible :). J'ai une table où l'une des colonnes est nommée type. Je voudrais sélectionner 3 enregistrements pour chaque type dans cette colonne. Est-ce possible?SQL - Donnez-moi 3 visites pour chaque type seulement

Notez également que j'utilise MySQL et Sphinx.

MISE À JOUR: Structure de la table

id  title  type 
1  AAAA   string1 
2  CCCC   string2 
3  EEEE   string2 
4  DDDD   string2 
5  FFFF   string2 
6  BBBB   string2 
6  BBBB   string2 

Ce que je veux que mon MySQL pour revenir est (jusqu'à 3 enregistrements pour chaque type commandé par titre):

id  title  type 
1  AAAA   string1 
6  BBBB   string2 
2  CCCC   string2 
4  DDDD   string2 
+3

D'abord, presque rien n'est impossible. Deuxièmement, pourquoi ne pas montrer votre structure de table et ce que vous avez essayé jusqu'ici. – ircmaxell

Répondre

12
select id, title, type 
from (select id, title, type, 
       @num := if(@group = type, @num + 1, 1) as row_number, 
       @group := type as dummy 
     from your_table 
     order by type, title) as x 
where row_number <= 3 

(! Utilise a different article sur le même site que Martin Wickman's answer)

+0

Très très gentil! – xpepermint

+0

+1 pour l'ordre fixe par – RichardTheKiwi

0

Découvrez this article. Compte tenu:

+--------+------------+-------+ 
| type | variety | price | 
+--------+------------+-------+ 
| apple | gala  | 2.79 | 
| apple | fuji  | 0.24 | 
| apple | limbertwig | 2.87 | 
| orange | valencia | 3.59 | 
| orange | navel  | 9.36 | 
| pear | bradford | 6.05 | 
| pear | bartlett | 2.14 | 
| cherry | bing  | 2.55 | 
| cherry | chelan  | 6.33 | 
+--------+------------+-------+ 

Requête:

select type, variety, price 
from fruits 
where (
    select count(*) from fruits as f 
    where f.type = fruits.type and f.price < fruits.price 
) <= 2; 
+0

Cette requête montrera des liens, donc si 4 fruits ont le même prix, ils montrent tous (au lieu de 3). Il n'y a pas eu non plus de tentative de lien vers la question. – RichardTheKiwi

+0

Si six variétés de pommes partageaient le même prix, le prix le plus bas, tous les six seraient retournés. Mais l'exemple de l'OP Je pense que id est probablement un identifiant unique (si, c'est-à-dire, les deux "6" sont produits à la suite d'un JOIN) et vous pouvez utiliser la colonne id au lieu de la colonne des prix un résultat correct garanti. –

2

Lorsque la table est grande et la collecte est plus imprévisible, la numérotation des lignes doit être trié par type dans la requête interne pour que les variables à effet latéral fonctionnent.

select id, title, type 
from (select id, title, type, 
     @r := CASE WHEN @g = type THEN @r+1 ELSE 1 END r, 
     @g := type 
     from tbl 
     order by type, title) as x 
where row_number <= 3 
# order by type, title 

Une autre façon de le faire sans utiliser des variables côté effectuer, si deux enregistrements sont exactement les mêmes sur (titre, type, id), est donné ci-dessous. Cela utilise uniquement SQL standard ANSI SQL92. Il peut être plus lent que ce qui précède cependant.

select A.id, A.title, A.type 
from tbl A 
left join tbl B on 
    A.title = B.title and 
    (A.type < B.type or 
    (A.type = B.type and A.id < A.id)) 
group by A.id, A.title, A.type 
having count(B.title) <= 2 
+0

Oui, j'ai repéré cela et fait cette correction avant que cela a été posté. –

2

Si vous avez un index sur (type, title), et vous connaissez les valeurs possibles pour type, je crois que SQL dynamique est la voie à suivre (pour une fois) pour une meilleure performance.

Pour chaque valeur possible de type, ajoutez une union et une sélection pour ce type spécifique. La requête finale ressemblera la requête suivante:

(select * from t1 where type = 'string1' order by title limit 3) 
    union all 
(select * from t1 where type = 'string2' order by title limit 3) 
    union all 
(select * from t1 where type = 'string3' order by title limit 3); 

Il exécute en moins de 1 seconde sur une table avec 1.000.000 lignes, alors que les solutions autres (Martins & Cyberkiwis) prend environ 11 secondes. La différence est que la requête unioned ci-dessus peut extraire les trois premières entrées de titre pour chaque type, puis stop, tandis que la fonction d'analyse simulée doit analyser la totalité de la table.

+0

Ma base de données a 200k enregistrements et il y a plus de 500 types. Que suggérez-vous? – xpepermint

+0

@xpepermint, rendez-vous avec la solution Martins. Sachez simplement que cela deviendra plus lent à mesure que vous ajouterez des enregistrements. À un certain point, il deviendra plus rapide d'effectuer 500 requêtes dans une boucle. Selon votre configuration, cela peut déjà être le cas. Vous devez vous mesurer. – Ronnis

Questions connexes