MySQLを使用して、テーブル内のレコードインデックスを含む列をどのように生成できますか?


100

クエリから実際の行番号を取得する方法はありますか?

scoreというフィールドでleague_girlというテーブルを注文できるようにしたいのですが、そして、ユーザー名とそのユーザー名の実際の行位置を返します。

ユーザーをランク付けしたいので、特定のユーザーがどこにいるかがわかります。ジョーは200のうち100位です。

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

ここでいくつかの解決策を見てきましたが、それらのほとんどを試しましたが、実際には行番号を返しません。

私はこれを試しました:

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

派生した

...しかし、それは行の位置を返さないようです。

何か案は?


行はフィールド名ですか、それとも主キーで並べ替えますか?
Sarfraz 2010年

SQLでは、行番号は本当に重要ではありません。あなたがすべきことは、自動インクリメントの主キーをテーブルに追加することです。
simendsjo

9
主キーは実際の行位置に対して信頼性がないため、行識別子は絶対に使用しないでください。
TheBounder

3
さらに、行番号は静的な値ではないと私が想定するスコアの関数であるため、自動インクリメントされた値(主キーかどうか)にすると、意図した結果が得られません。
kasperjj 2010年

カスタム関数のために醜いものを保存したいかもしれません。datamakessense.com/ mysql
rownum

回答:


174

次のことを試してみてください。

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

このJOIN (SELECT @curRow := 0)パーツでは、個別のSETコマンドを必要とせずに変数の初期化が可能です。

テストケース:

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);

テストクエリ:

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;

結果:

+----------+----------+-------+------------+
| position | username | score | row_number |
+----------+----------+-------+------------+
|        3 | c        |    75 |          1 |
|        5 | e        |    55 |          2 |
|        6 | f        |    80 |          3 |
+----------+----------+-------+------------+
3 rows in set (0.00 sec)

19
また、初期化することができます@curRow置き換えることでJOIN、このように、コンマでステートメントを:FROM league_girl l, (SELECT @curRow := 0) r
マイク・

2
@マイク:それは本当です。そして、それもおそらくきちんとしています。このヒントを共有していただきありがとうございます。
Daniel Vassallo

2
@smhnaji MySQLでは、すべての「派生テーブル」に名前を付ける必要があります。"r"と呼ぶことにしました:) ...この場合はほとんど目的がありませんが、通常は、実際のテーブルであるかのように、派生テーブルの属性を参照するために使用します。
ダニエルヴァッサロ

20
この行番号は順序付けが行われる前に計算されるため、順序が行順序を変更すると、番号が乱れる可能性があることに注意してください。
グリム...

7
この行番号を後に計算する方法はありORDER BYますか?
Pierre de LESPINAY 2012年


7

ここに私が使用したテンプレートの構造があります:

  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

そして、これが私の作業コードです:

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

完璧..パラメータとしてサブクエリを再利用することができます魅力とテンプレートのように動作します
Zavael

このソリューションは、ベースクエリがGROUP BYを使用する場合にも機能します
Dave R

4

あなたも使うことができます

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

カウンタ変数を初期化します。


3
@curRow現在のセッションでこのクエリを最後に実行したときの値がまだ残っている可能性があります。
Bill Karwin、

正しいが、同じ接続インスタンスで再クエリを実行する場合のみ。接続が閉じられると、ローカル変数は自動的に破棄されます。
ハース

はい、それは私が「現在のセッションで」と言ったときに私が意味したことです。
ビルカーウィン2014年

3

MySQLがサポートしていると仮定すると、標準SQLサブクエリでこれを簡単に行うことができます。

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;

表示される結果の量が多い場合、これは少し遅くなり、代わりに自己結合に切り替える必要があります。


3

フィールドスコアで注文した後の特定のユーザーの位置だけを知りたい場合は、フィールドスコアが現在のユーザースコアより高いすべての行をテーブルから選択するだけです。そして、返された行番号+ 1を使用して、この現在のユーザーのどの位置を知るか

テーブルがleague_girlでプライマリフィールドがidであるとすると、これを使用できます。

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

0

元の回答は非常に役に立ちましたが、挿入していた行番号に基づいて特定の行セットも取得したいと思いました。そのため、挿入した行番号を参照できるように、元の回答全体をサブクエリで囲みました。

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;

サブクエリにサブクエリを含めることはあまり効率的ではないので、SQLサーバーでこのクエリを処理するか、テーブル全体をフェッチしてアプリケーション/ Webサーバーで事後に行を操作することで、より良い結果が得られるかどうかをテストする価値があります。 。

個人的には、私のSQLサーバーは過度にビジーではないので、ネストされたサブクエリを処理することをお勧めします。


0

OPがmysql回答を求めているのはわかっていますが、他の回答がうまくいかないことがわかったので、

  • それらのほとんどは失敗します order by
  • または、単に非常に非効率的であり、脂肪質のテーブルに対してクエリが非常に遅くなります

したがって、私のような他の人のために時間を節約するには、データベースから行を取得した後で行にインデックスを付けるだけです

PHPの例:

$users = UserRepository::loadAllUsersAndSortByScore();

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

ページングにオフセットと制限を使用するPHPの例:

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

$users = UserRepository::loadAllUsersAndSortByScore();

foreach($users as $index=>&$user){
    $user['rank'] = $index+1+($limit*($offset-1));
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.