2008-11-07 6 views
11

Je cours un site Web où les utilisateurs peuvent signaler des articles (par exemple des images). Les éléments sont stockés dans une base de données MySQL.Comment sélectionner 3 éléments maximum par utilisateur dans MySQL?

Je veux interroger pour les dix derniers articles publiés MAIS avec la contrainte d'un maximum de 3 articles peuvent provenir d'un seul utilisateur.

Quelle est la meilleure façon de le faire? Ma solution préférée est une contrainte qui est mise sur la requête SQL demandant les dix derniers éléments. Mais les idées sur la façon de configurer la base de données sont les bienvenues.

Merci d'avance!

BR

Répondre

5

Il est assez facile avec une sous-requête corrélative:

SELECT `img`.`id` , `img`.`userid` 
FROM `img` 
WHERE 3 > (
SELECT count(*) 
FROM `img` AS `img1` 
WHERE `img`.`userid` = `img1`.`userid` 
AND `img`.`id` > `img1`.`id`) 
ORDER BY `img`.`id` DESC 
LIMIT 10 

La requête suppose que plus id moyen supplémentaire plus tard

sous-requêtes sont Corrélés un outil puissant! :-)

+0

Pouvez-vous exprimer en anglais simple comment cela fonctionne? Je ne comprends pas. – Tomalak

+0

La sous-requête élimine toutes les lignes pour lesquelles il existe déjà trois lignes avec le même ID utilisateur et un ID d'image inférieur. Je pense que le symbole supérieur à la sous-requête peut être inversé. –

+0

Ceci est un exemple de SQL étant plus expressif que l'anglais simple :-) Tom H. a donné une bonne explication; et oui, je suis sûr que le symbole supérieur est correct – Incidently

2

Cela est difficile parce que MySQL ne supporte pas la clause LIMIT sur les sous-requêtes. Si elle l'a fait, ce serait plutôt banal ... Mais hélas, voici mon approche naïve:

SELECT 
    i.UserId, 
    i.ImageId 
FROM 
    UserSuppliedImages i 
WHERE 
    /* second valid ImageId */ 
    ImageId = (
    SELECT MAX(ImageId) 
    FROM UserSuppliedImages 
    WHERE UserId = i.UserId 
) 
    OR 
    /* second valid ImageId */ 
    ImageId = (
    SELECT MAX(ImageId) 
    FROM UserSuppliedImages 
    WHERE UserId = i.UserId 
     AND ImageId < (
     SELECT MAX(ImageId) 
     FROM UserSuppliedImages 
     WHERE UserId = i.UserId 
    ) 
    ) 
    /* you get the picture... 
    the more "per user" images you want, the more complex this will get */ 
LIMIT 10; 

Vous n'avez pas parlé d'avoir un ordre de résultat préféré, donc (en supposant ImageId sélectionne les dernières images est une valeur auto-incrémentante ascendante).

A titre de comparaison, sur SQL Server même ressembler à ceci:

SELECT TOP 10 
    img.ImageId, 
    img.ImagePath, 
    img.UserId 
FROM 
    UserSuppliedImages img 
WHERE 
    ImageId IN (
    SELECT TOP 3 ImageId 
    FROM UserSuppliedImages 
    WHERE UserId = img.UserId 
) 
0

Je voudrais tout d'abord sélectionner 10 utilisateurs distincts, puis en sélectionnant des images de chacun de ces utilisateurs avec une limite 3, peut-être par une union de Tout cela et limiter cela à 10.

Cela réduirait au minimum les données que vous devez traiter à un montant raisonnable.

Questions connexes