Avec la table MySQL suivante:
+-----------------------------+
+ id INT UNSIGNED +
+ name VARCHAR(100) +
+-----------------------------+
Comment puis-je sélectionner une seule ligne ET sa position parmi les autres lignes du tableau, une fois triées par name ASC
. Donc, si les données de la table ressemblent à ceci, lorsqu'elles sont triées par nom:
+-----------------------------+
+ id | name +
+-----------------------------+
+ 5 | Alpha +
+ 7 | Beta +
+ 3 | Delta +
+ ..... +
+ 1 | Zed +
+-----------------------------+
Comment pourrais-je sélectionner la Beta
ligne pour obtenir la position actuelle de cette ligne? L'ensemble de résultats que je recherche serait quelque chose comme ceci:
+-----------------------------+
+ id | position | name +
+-----------------------------+
+ 7 | 2 | Beta +
+-----------------------------+
Je peux faire un simple SELECT * FROM tbl ORDER BY name ASC
puis énumérer les lignes en PHP, mais il semble inutile de charger un ensemble de résultats potentiellement volumineux juste pour une seule ligne.
sql
mysql
analytic-functions
leepowers
la source
la source
Réponses:
Utilisez ceci:
SELECT x.id, x.position, x.name FROM (SELECT t.id, t.name, @rownum := @rownum + 1 AS position FROM TABLE t JOIN (SELECT @rownum := 0) r ORDER BY t.name) x WHERE x.name = 'Beta'
... pour obtenir une valeur de position unique. Ce:
SELECT t.id, (SELECT COUNT(*) FROM TABLE x WHERE x.name <= t.name) AS position, t.name FROM TABLE t WHERE t.name = 'Beta'
... donnera aux cravates la même valeur. IE: S'il y a deux valeurs à la deuxième place, elles auront toutes les deux une position de 2 lorsque la première requête donnera une position de 2 à l'une d'elles et de 3 à l'autre ...
la source
position
, mais c'est parfait.C'est la seule façon dont je peux penser:
SELECT `id`, (SELECT COUNT(*) FROM `table` WHERE `name` <= 'Beta') AS `position`, `name` FROM `table` WHERE `name` = 'Beta'
la source
name <= 'Beta'
placeposition
valeurs pour les cravates.LIMIT 1
là-dedans? En cas d'égalité, vous n'obtiendrez qu'une seule ligne avec la dernière position de l'égalité.name
champ est unique, il n'y a aucune raison de rendre la requête plus complexe. S'il ne peut pas - attendons ses attentes de résultat pour les noms à égalité.Si la requête est simple et que la taille du jeu de résultats renvoyé est potentiellement importante, vous pouvez essayer de la diviser en deux requêtes.
La première requête avec un critère de filtrage restreint juste pour récupérer les données de cette ligne, et la deuxième requête utilise la clause
COUNT
withWHERE
pour calculer la position.Par exemple dans votre cas
Requête 1:
SELECT * FROM tbl WHERE name = 'Beta'
Requête 2:
SELECT COUNT(1) FROM tbl WHERE name >= 'Beta'
Nous utilisons cette approche dans une table avec 2M d'enregistrement et c'est beaucoup plus évolutif que l'approche d'OMG Ponies.
la source
Les autres réponses me semblent trop compliquées.
Voici un exemple simple , disons que vous avez une table avec des colonnes:
et vous voulez trier les userids par points et obtenir la position de la ligne (le "classement" de l'utilisateur), alors vous utilisez:
SET @row_number = 0; SELECT (@row_number:=@row_number + 1) AS num, userid, points FROM ourtable ORDER BY points DESC
num
vous donne la position de ligne (classement).Si vous avez MySQL 8.0+, vous pouvez utiliser ROW_NUMBER ()
la source
La position d'une ligne dans le tableau représente le nombre de lignes "meilleures" que la ligne ciblée.
Donc, vous devez compter ces lignes.
SELECT COUNT (*) + 1 FROM
table
WHEREname
<'Beta'En cas d'égalité, la position la plus élevée est renvoyée.
Si vous ajoutez une autre ligne avec le même nom "Beta" après la ligne "Beta" existante, la position renvoyée sera toujours 2, car ils partageraient la même place dans la classification.
J'espère que cela aidera les gens qui chercheront quelque chose de similaire à l'avenir, car je pense que le propriétaire de la question a déjà résolu son problème.
la source
J'ai un problème très similaire, c'est pourquoi je ne poserai pas la même question, mais je vais partager ici ce que j'ai fait, j'ai dû utiliser aussi un groupe par, et commander par AVG. Il y a des étudiants, avec des signatures et socore, et j'ai dû les classer (en d'autres termes, je calcule d'abord l'AVG, puis les ordonne en DESC, et enfin j'ai besoin d'ajouter la position (rang pour moi), donc j'ai quelque chose de Très similaire comme la meilleure réponse ici, avec quelques changements qui s'ajustent à mon problème):
Je mets enfin la
position
colonne (rank for me) dans le SELECT externeSET @rank=0; SELECT @rank := @rank + 1 AS ranking, t.avg, t.name FROM(SELECT avg(students_signatures.score) as avg, students.name as name FROM alumnos_materia JOIN (SELECT @rownum := 0) r left JOIN students ON students.id=students_signatures.id_student GROUP BY students.name order by avg DESC) t
la source
J'étais en train de parcourir la réponse acceptée et cela me semblait un peu compliqué, alors en voici la version simplifiée.
SELECT t,COUNT(*) AS position FROM t WHERE name <= 'search string' ORDER BY name
la source
J'ai des types de problèmes similaires où j'ai besoin du rang ( index ) de la table
order by votes desc
. Ce qui suit fonctionne très bien pour moi.Select *, ROW_NUMBER() OVER(ORDER BY votes DESC) as "rank" From "category_model" where ("model_type" = ? and "category_id" = ?)
la source
peut être ce dont vous avez besoin avec une syntaxe d'ajout
alors utilise
SELECT * FROM tbl ORDER BY name ASC LIMIT 1
si vous n'avez besoin que d'une ligne ..
la source