2011-07-03 4 views
0

je les tableaux ci-dessous dans la base de données de mon jeu:SQL: requête avec sous-requêtes complexes

rankedUp (image_id, user_id, created_at) 
globalRank (image_id, rank) 
matchups (user_id, image_id1, image_id2) 

Tous image_ids dans le tableau globalRank se voient attribuer un rang qui est un flotteur de 0 à 1

En supposant que je l'utilisateur connecté actuel de la valeur « user_id » de l'utilisateur, je suis à la recherche d'une requête qui retourne une paire de ids d'image (imageid1, imageid2) tel que:

  1. imageid1 a rang inférieur à imageid2 mais aussi la prochaine Ra le plus élevé nk moins imageid2
  2. tableau confrontations n'a pas (ID utilisateur, imageid1, imageid2) ou (ID utilisateur, imageid2, imageid1)
  3. tableau rankedup n'a pas (ID utilisateur, imageid1) ou si elle le fait, la colonne createdat est plus ancienne que X heures

ce que j'ai jusqu'à présent pour la condition 1 est la suivante:

SELECT lowerImages.image_id AS lower_image, higherImages.image_id AS higher_image 
FROM global_rank AS lowerImages, global_rank AS higherImages 
WHERE lowerImages.rank < higherImages.rank 
AND lowerImages.image_id = ( 
    SELECT image_id 
    FROM (
     SELECT image_id 
     FROM global_rank 
     WHERE rank < higherImages.rank 
     ORDER BY rank DESC 
     LIMIT 1 , 1 
     ) AS tmp 
    ) 

mais cela ne fonctionne pas parce que je ne peux pas faire référence à higherImages.rank dans la sous-requête.

Est-ce que quelqu'un sait comment je pourrais satisfaire à toutes ces exigences dans une requête?

Merci pour votre aide

EDIT:

J'ai maintenant cette requête, mais je ne sais pas sur l'efficacité et je dois le tester pour l'exactitude:

SELECT lowerImages.image_id AS lower_image, 
     max(higherImages.image_id) AS higher_image 
FROM global_rank AS lowerImages, global_rank AS higherImages 
WHERE lowerImages.rank < higherImages.rank 

AND 1 NOT IN (select 1 from ranked_up where 
    lowerImages.image_id = ranked_up.image_id 
    AND ranked_up.user_id = $user_id 
    AND ranked_up.created_at > DATE_SUB(NOW(), INTERVAL 1 DAY)) 

AND 1 NOT IN (
    SELECT 1 from matchups where user_id = $userId 
      AND lower_image_id = lowerImages.image_id 
      AND higher_image_id = higherImages.image_id 
      UNION 
      SELECT 1 from matchups where user_id = $user_id 
      AND lower_image_id = higherImages.image_id 
      AND higher_image_id = lowerImages.image_id 
) 
GROUP BY 1 

le " pas dans "les déclarations que j'utilise sont tous indexés donc ils devraient courir vite. Le problème de l'efficacité que j'ai est le groupe par sélection et des tables de global_rank


Cette question est une révision de Pretty Complex SQL Query, qui ne devrait plus être répondu.

+0

Quel moteur DB et quelle version s'il vous plaît? MySQL? – gbn

+0

Désolé, c'est MySQL – user257543

+0

Je suis content de voir que vous avez supprimé l'exigence 'randomness'; cela le rend un peu plus facile. –

Répondre

0
select 
(
select image_id, rank from 
rankedup inner join globalRank 
on rankedup.image_id = globalRank .image_id 
where user_id = XXX 
limit 1, 1 
) as highest, 
(
select image_id, rank from 
rankedup inner join globalRank 
on rankedup.image_id = globalRank .image_id 
where user_id = XXX 
limit 2, 1 
) as secondhighest 

J'utilise normalement SQL Server, mais je pense que la traduction pour mysql :)

0

Cela devrait faire l'affaire:

SELECT lowerImages.*, higherImages.* 
FROM globalrank AS lowerImages, globalrank AS higherImages 
WHERE lowerImages.rank < higherImages.rank 
AND lowerImages.image_id = ( 
    SELECT image_id 
    FROM (
     SELECT image_id 
     FROM globalrank 
     WHERE rank < higherImages.rank 
     ORDER BY rank DESC 
     LIMIT 1,1 
     ) AS tmp 
    ) 
AND NOT EXISTS (
    SELECT * FROM matchups 
    WHERE user_id = $user_id 
    AND ((image_id1 = lowerImages.image_id AND image_id2 = higherImages.image_id) 
     OR (image_id2 = lowerImages.image_id AND image_id1 = higherImages.image_id)) 
) 
AND higherImages.image_id NOT IN (
    SELECT image_id FROM rankedup 
    WHERE created_at < DATE_ADD(NOW(), INTERVAL 1 DAY) 
    AND USER_ID <> $user_id 
) 
ORDER BY higherImages.rank 

Je suppose que le PKS des matchups et rankup inclut toutes les colonnes de ces tables. Cela permettrait aux deux sous-requêtes d'utiliser les index PK. Vous voudrez probablement un index ordonné sur globalrank.rank pour accélérer la première sous-requête.

+0

ressemble à la référence à higherImages.rank dans la sous-requête provoque l'échec de la requête entière – user257543