2009-07-17 5 views
1

J'ai une table MySQL de base, termes, composé d'un id et terme sur le terrain. Je veux créer un index de dictionnaire trié alphabétiquement (dans le sens littéral), qui énumérerait dix 10 termes au-dessus du terme sélectionné, et 20 au-dessous. Un exemple de ceci peut être trouvé ici http://www.urbandictionary.com/define.php?term=GD2&defid=3561357 où sur la colonne de gauche vous voyez le terme actuel mis en évidence, et un certain nombre de termes au-dessus, et certains ci-dessous, tous classés par ordre alphabétique.Référencer une sous-sélection MySQL dans une autre requête

Comme nous le savons tous, MySQL ne supporte pas ROW_NUMBER() ou une fonction similaire, nous finissons par avoir recours à des variables et des sous-sélections utilisateur. Je ne peux pas non plus créer une vue avec des variables définies par l'utilisateur, car MySQL ne le permet pas. Voici ce que je réussi à trouver (et ça marche):

 SET @row_num := 0; 

     SELECT 
      @term_index := ordered.row_number 
     FROM 
     (
      SELECT 
       @row_num := @row_num + 1 AS row_number, terms.* 
      FROM 
       terms 
      ORDER BY 
       term ASC 
     ) AS ordered 
     WHERE 
      ordered.term = 'example term'; 

     SET @row_num := 0; 

     SELECT * 
     FROM 
     (
      SELECT 
       @row_num := @row_num + 1 AS row_number, terms.* 
      FROM 
       terms 
      ORDER BY 
       term ASC 
     ) AS ordered 
     WHERE 
      row_number BETWEEN @term_index - 10 AND @term_index + 20 

Le premier SELECT trouve simplement le numéro de la ligne de notre terme cible dans l'ensemble de la table des termes classés par ordre alphabétique. Le second SELECT utilise cette information pour obtenir 10 termes au-dessus et 20 termes en dessous.

Je me demande s'il existe un moyen d'éviter d'exécuter la sous-sélection dans la deuxième requête SELECT et de ne faire référence qu'à la première commandée. Existe-t-il un moyen plus efficace d'accomplir cela sans devoir recourir à la création manuelle d'une table temporaire? Qu'est-ce que je fais mal ici?

Répondre

1

Mise à jour:

Voir cet article dans mon blog pour plus de détails de performance:


Si votre term est indexé, vous pouvez juste lancer:

SELECT * 
FROM (
     SELECT * 
     FROM terms 
     WHERE term <= @myterm 
     ORDER BY 
       term DESC 
     LIMIT 10 
     ) q 
UNION ALL 
SELECT * 
FROM (
     SELECT * 
     FROM terms 
     WHERE term > @myterm 
     ORDER BY 
       term 
     LIMIT 20 
     ) q 
ORDER BY 
     term 

, qui sera plus efficace.

+0

Cela fonctionne effectivement et est plus simple et plus rapide pour mes fins. Cependant, les deux sous-requêtes doivent être aliasé selon MySQL et la première sous-requête doit être triée dans l'ordre ASC pour que cela fonctionne. Merci beaucoup. – Salaryman

+0

@Salaryman: à droite, fixant. – Quassnoi

+1

@Salaryman: mais la première sous-requête doit être 'DESC', n'est-ce pas? Il devrait sélectionner * last * '10' valeurs qui sont moins égales à un donné. – Quassnoi

Questions connexes