Une option consiste à utiliser une variable de classement, telle que la suivante:
SELECT first_name,
age,
gender,
@curRank := @curRank + 1 AS rank
FROM person p, (SELECT @curRank := 0) r
ORDER BY age;
La (SELECT @curRank := 0)
pièce permet l'initialisation de la variable sans nécessiter une SET
commande séparée .
Cas de test:
CREATE TABLE person (id int, first_name varchar(20), age int, gender char(1));
INSERT INTO person VALUES (1, 'Bob', 25, 'M');
INSERT INTO person VALUES (2, 'Jane', 20, 'F');
INSERT INTO person VALUES (3, 'Jack', 30, 'M');
INSERT INTO person VALUES (4, 'Bill', 32, 'M');
INSERT INTO person VALUES (5, 'Nick', 22, 'M');
INSERT INTO person VALUES (6, 'Kathy', 18, 'F');
INSERT INTO person VALUES (7, 'Steve', 36, 'M');
INSERT INTO person VALUES (8, 'Anne', 25, 'F');
Résultat:
+------------+------+--------+------+
| first_name | age | gender | rank |
+------------+------+--------+------+
| Kathy | 18 | F | 1 |
| Jane | 20 | F | 2 |
| Nick | 22 | M | 3 |
| Bob | 25 | M | 4 |
| Anne | 25 | F | 5 |
| Jack | 30 | M | 6 |
| Bill | 32 | M | 7 |
| Steve | 36 | M | 8 |
+------------+------+--------+------+
8 rows in set (0.02 sec)
partition by gender
partie de la fonction analytique (qui "numérote" la valeur de rang par sexe et non pour le résultat global)Voici une solution générique qui attribue un rang dense sur la partition aux lignes. Il utilise des variables utilisateur:
Notez que les affectations de variables sont placées à l'intérieur du
CASE
expression. Ceci (en théorie) s'occupe de l'ordre de la question d'évaluation. LeIS NOT NULL
est ajouté pour gérer les problèmes de conversion de type de données et de court-circuit.PS: Il peut facilement être converti en numéro de ligne sur la partition en supprimant toutes les conditions qui vérifient l'égalité.
Démo sur db <> fiddle
la source
ELSE @rank_count := @rank_count + 1
ORDER BY gender, age DESC
?Bien que la réponse la plus votée soit classée, elle ne se partitionne pas, vous pouvez faire une auto-jointure pour que le tout soit également partitionné:
Cas d'utilisation
Réponse :
la source
Un ajustement de la version de Daniel pour calculer le percentile avec le rang. Deux personnes avec les mêmes notes obtiendront également le même rang.
Résultats de la requête pour un exemple de données -
la source
Combinaison de la réponse de Daniel et de Salman. Cependant, le rang ne sera pas donné car la séquence continue avec des liens existe. Au lieu de cela, il saute le rang au suivant. Donc, le maximum atteint toujours le nombre de lignes.
Schéma et scénario de test:
Production:
la source
À partir de MySQL 8, vous pouvez enfin utiliser les fonctions de fenêtre également dans MySQL: https://dev.mysql.com/doc/refman/8.0/en/window-functions.html
Votre requête peut être écrite exactement de la même manière:
la source
@Sam, votre point est excellent dans le concept, mais je pense que vous avez mal compris ce que disent les documents MySQL sur la page référencée - ou je ne comprends pas :-) - et je voulais juste ajouter ceci pour que si quelqu'un se sent mal à l'aise avec le @ Réponse de Daniel, ils seront plus rassurés ou du moins creuseront un peu plus.
Vous voyez que l'
"@curRank := @curRank + 1 AS rank"
intérieurSELECT
n'est pas "une seule instruction", c'est une partie "atomique" de l'instruction, donc elle devrait être sûre.Le document auquel vous faites référence continue pour montrer des exemples où la même variable définie par l'utilisateur dans 2 parties (atomiques) de l'instruction, par exemple,
"SELECT @curRank, @curRank := @curRank + 1 AS rank"
,.On pourrait dire que
@curRank
c'est utilisé deux fois dans la réponse de @ Daniel: (1) le"@curRank := @curRank + 1 AS rank"
et (2) le"(SELECT @curRank := 0) r"
mais puisque le deuxième usage fait partie de laFROM
clause, je suis presque sûr qu'il est garanti d'être évalué en premier; ce qui en fait essentiellement une deuxième et précédente déclaration.En fait, sur cette même page de documentation MySQL que vous avez référencée, vous verrez la même solution dans les commentaires - cela pourrait être d'où @Daniel l'a obtenu; oui, je sais que ce sont les commentaires, mais ce sont des commentaires sur la page officielle de la documentation et cela a un certain poids.
la source
La solution la plus simple pour déterminer le rang d'une valeur donnée est de compter le nombre de valeurs devant elle. Supposons que nous ayons les valeurs suivantes:
30
valeurs sont considérées comme 3ème40
valeurs sont considérées comme 6e (rang) ou 4e (rang dense)Revenons maintenant à la question initiale. Voici quelques exemples de données triées comme décrit dans OP (les rangs attendus sont ajoutés à droite):
Pour calculer
RANK() OVER (PARTITION BY Gender ORDER BY Age)
pour Sarah , vous pouvez utiliser cette requête:Pour calculer
RANK() OVER (PARTITION BY Gender ORDER BY Age)
pour toutes les lignes que vous pouvez utiliser cette requête:Et voici le résultat (les valeurs jointes sont ajoutées à droite):
la source
Si vous souhaitez classer une seule personne, vous pouvez effectuer les opérations suivantes:
Ce classement correspond à la fonction oracle RANK (où si vous avez des personnes du même âge, elles obtiennent le même rang, et le classement qui suit n'est pas consécutif).
C'est un peu plus rapide que d'utiliser l'une des solutions ci-dessus dans une sous-requête et de la sélectionner pour obtenir le classement d'une personne.
Cela peut être utilisé pour classer tout le monde, mais c'est plus lent que les solutions ci-dessus.
la source
Person
tableau augmente. C'est O (n ^ 2) vs O (n) plus lent.Pour éviter le " cependant " dans la réponse d'Erandac en combinaison des réponses de Daniel et Salman, on peut utiliser l'une des "solutions de contournement de partition" suivantes
Le classement de la partition dans la troisième variante de cet extrait de code renverra des numéros de classement continus. cela conduira à une structure de données similaire au
rank() over partition by
résultat. A titre d'exemple, voir ci-dessous. En particulier, partitionSequence commencera toujours par 1 pour chaque nouveau partitionRank , en utilisant cette méthode:la source
la source