2010-04-29 4 views
2

J'ai la requête suivante:Existe-t-il un moyen de LIMITER les résultats par groupe de résultats dans MySQL?

SELECT title, karma, DATE(date_uploaded) as d 
FROM image 
ORDER BY d DESC, karma DESC 

Cela me donnera une liste d'enregistrements d'images, d'abord trié par jour récent, puis par la plupart karma.

Il manque juste une chose: je veux seulement obtenir les images x avec le karma le plus élevé par jour. Par exemple, par jour, je veux seulement les 10 images les plus karma. Je pourrais bien sûr lancer plusieurs requêtes, une par jour, puis combiner les résultats. Je me demandais s'il y a un moyen plus intelligent qui fonctionne encore bien. Je suppose que ce que je cherche est une façon d'utiliser LIMIT x, y par groupe de résultats?

Répondre

4

Vous pouvez le faire en émulant ROW_NUMBER en utilisant des variables.

SELECT d, title, karma 
FROM (
    SELECT 
     title, 
     karma, 
     DATE(date_uploaded) AS d, 
     @rn := CASE WHEN @prev = UNIX_TIMESTAMP(DATE(date_uploaded)) 
        THEN @rn + 1 
        ELSE 1 
       END AS rn, 
     @prev := UNIX_TIMESTAMP(DATE(date_uploaded)) 
    FROM image, (SELECT @prev := 0, @rn := 0) AS vars 
    ORDER BY date_uploaded, karma DESC 
) T1 
WHERE rn <= 3 
ORDER BY d, karma DESC 

Résultat:

'2010-04-26', 'Title9', 9 
'2010-04-27', 'Title5', 8 
'2010-04-27', 'Title6', 7 
'2010-04-27', 'Title7', 6 
'2010-04-28', 'Title4', 4 
'2010-04-28', 'Title3', 3 
'2010-04-28', 'Title2', 2 

Quassnoi a un bon article sur ce qui explique la technique dans plus de détails: Emulating ROW_NUMBER() in MySQL - Row sampling.

données de test:

CREATE TABLE image (title NVARCHAR(100) NOT NULL, karma INT NOT NULL, date_uploaded DATE NOT NULL); 
INSERT INTO image (title, karma, date_uploaded) VALUES 
('Title1', 1, '2010-04-28'), 
('Title2', 2, '2010-04-28'), 
('Title3', 3, '2010-04-28'), 
('Title4', 4, '2010-04-28'), 
('Title5', 8, '2010-04-27'), 
('Title6', 7, '2010-04-27'), 
('Title7', 6, '2010-04-27'), 
('Title8', 5, '2010-04-27'), 
('Title9', 9, '2010-04-26'); 
+0

Merci beaucoup pour l'effort considérable. J'ai quelques soucis au sujet de la performance mais le testerai, je peux avoir besoin de cacher la sortie quand même :) – Ferdy

+0

@Ferdy: Pour améliorer la performance de cette requête, ajoutez un index combiné sur '(date_uploaded, karma)'. –

0

Peut-être que cela fonctionnera:

titre SELECT, karma, DATE (date_uploaded) comme d de l'image img WHERE id IN ( SELECT id de l'image WHERE DATE (date_uploaded) = DATE (img.date_uploaded) COMMANDER PAR karma DESC LIMIT 10 ) COMMANDER PAR d DESC, karma DESC

Mais ce n'est pas très efficace, car vous n'avez pas d'index le DATE (date_uploaded) (je ne sais pas si cela serait possible, mais je suppose que ce n'est pas le cas). Au fur et à mesure que la table grossit, cela peut coûter très cher au CPU. Il pourrait être plus simple d'avoir une boucle dans votre code :-).

Questions connexes