web-dev-qa-db-fra.com

Avec MySQL, comment puis-je générer une colonne contenant l'index d'enregistrement dans une table?

Est-il possible d'obtenir le numéro de ligne réel d'une requête?

Je veux pouvoir commander une table appelée league_girl par un champ appelé score; et renvoie le nom d'utilisateur et la position réelle de ce nom d'utilisateur.

Je veux classer les utilisateurs afin que je puisse dire où un utilisateur particulier est, à savoir. Joe occupe la position 100 sur 200, c’est-à-dire.

User Score Row
Joe  100    1
Bob  50     2
Bill 10     3

J'ai déjà vu quelques solutions, mais j'ai essayé la plupart d'entre elles et aucune d'elles ne renvoie le numéro de ligne.

J'ai essayé ceci:

SELECT position, username, score
FROM (SELECT @row := @row + 1 AS position, username, score 
       FROM league_girl GROUP BY username ORDER BY score DESC) 

Comme dérivé 

... mais il ne semble pas retourner la position de la ligne.

Des idées?

97
TheBounder

Vous voudrez peut-être essayer ce qui suit:

SELECT  l.position, 
        l.username, 
        l.score,
        @curRow := @curRow + 1 AS row_number
FROM    league_girl l
JOIN    (SELECT @curRow := 0) r;

La partie JOIN (SELECT @curRow := 0) autorise l'initialisation de la variable sans nécessiter une commande SET séparée.

Cas de test:

CREATE TABLE league_girl (position int, username varchar(10), score int);
INSERT INTO league_girl VALUES (1, 'a', 10);
INSERT INTO league_girl VALUES (2, 'b', 25);
INSERT INTO league_girl VALUES (3, 'c', 75);
INSERT INTO league_girl VALUES (4, 'd', 25);
INSERT INTO league_girl VALUES (5, 'e', 55);
INSERT INTO league_girl VALUES (6, 'f', 80);
INSERT INTO league_girl VALUES (7, 'g', 15);

Requête de test:

SELECT  l.position, 
        l.username, 
        l.score,
        @curRow := @curRow + 1 AS row_number
FROM    league_girl l
JOIN    (SELECT @curRow := 0) r
WHERE   l.score > 50;

Résultat:

+----------+----------+-------+------------+
| position | username | score | row_number |
+----------+----------+-------+------------+
|        3 | c        |    75 |          1 |
|        5 | e        |    55 |          2 |
|        6 | f        |    80 |          3 |
+----------+----------+-------+------------+
3 rows in set (0.00 sec)
164
Daniel Vassallo
SELECT @i:=@i+1 AS iterator, t.*
FROM tablename t,(SELECT @i:=0) foo
37
Peter Johnson

Voici la structure de modèle que j'ai utilisée:

  select
          /*this is a row number counter*/
          ( select @rownum := @rownum + 1 from ( select @rownum := 0 ) d2 ) 
          as rownumber,
          d3.*
  from 
  ( select d1.* from table_name d1 ) d3

Et voici mon code de travail:

select     
           ( select @rownum := @rownum + 1 from ( select @rownum := 0 ) d2 ) 
           as rownumber,
           d3.*
from
(   select     year( d1.date ), month( d1.date ), count( d1.id )
    from       maindatabase d1
    where      ( ( d1.date >= '2013-01-01' ) and ( d1.date <= '2014-12-31' ) )
    group by   YEAR( d1.date ), MONTH( d1.date ) ) d3
6
goadreamer

Vous pouvez aussi utiliser

SELECT @curRow := ifnull(@curRow,0) + 1 Row, ...

pour initialiser la variable compteur.

4
Hearth

Si vous souhaitez simplement connaître la position d'un utilisateur spécifique après le classement par score de champ, vous pouvez simplement sélectionner toutes les lignes de votre tableau où le score de champ est supérieur au score de l'utilisateur actuel. Et utilisez le numéro de ligne renvoyé + 1 pour savoir quelle position de cet utilisateur actuel.

En supposant que votre table est "league_girl" et que votre champ principal soit "id", vous pouvez utiliser ceci:

SELECT count(id) + 1 as rank from league_girl where score > <your_user_score>
3
Heryno

En supposant que MySQL le supporte, vous pouvez facilement le faire avec une sous-requête SQL standard:

select 
    (count(*) from league_girl l1 where l2.score > l1.score and l1.id <> l2.id) as position,
    username,
    score
from league_girl l2
order by score;

Pour les grandes quantités de résultats affichés, cela sera un peu lent et vous voudrez plutôt passer à une auto-jointure.

3
ftzdomino

Je sais que le PO demande une réponse mysql, mais comme j'ai trouvé les autres réponses ne fonctionnaient pas pour moi, 

  • La plupart d'entre eux échouent avec order by 
  • Ou ils sont tout simplement très inefficaces et rendent votre requête très lente pour une grosse table

Donc, pour gagner du temps pour des gens comme moi, indexez simplement la ligne après l'avoir extraite de la base de données

exemple en PHP:

        $users = UserRepository::loadAllUsersAndSortByScore();

        foreach($users as $index=>&$user){
            $user['rank'] = $index+1;
        }

exemple dans PHP en utilisant offset et limit pour la pagination:

        $limit = 20; //page size
        $offset = 3; //page number

        $users = UserRepository::loadAllUsersAndSortByScore();

        foreach($users as $index=>&$user){
            $user['rank'] = $index+1+($limit*($offset-1));
        }
0
azerafati

J'ai trouvé la réponse originale extrêmement utile, mais je souhaitais également saisir un certain ensemble de lignes en fonction des numéros de ligne que j'inscrivais. En tant que tel, j'ai encapsulé la réponse originale complète dans une sous-requête afin de pouvoir référencer le numéro de ligne que j'étais en train d'insérer.

SELECT * FROM 
( 
    SELECT *, @curRow := @curRow + 1 AS "row_number"
    FROM db.tableName, (SELECT @curRow := 0) r
) as temp
WHERE temp.row_number BETWEEN 1 and 10;

Avoir une sous-requête dans une sous-requête n'est pas très efficace, il serait donc intéressant de vérifier si vous obtenez un meilleur résultat en laissant votre serveur SQL gérer cette requête, ou en récupérant la table entière et en laissant l'application/le serveur Web manipuler les lignes après coup. .

Personnellement, mon serveur SQL n'est pas trop occupé, il était donc préférable de gérer les sous-requêtes imbriquées.

0
BasicExp