MySQLでOracleのrownumのような行番号を付加する
MySQLでOracleのrownumのような行番号を付加する方法として、Web上でよく見かけるのは以下のようなユーザー変数を使ったSQL文で、2つのSQL文を発行しなければならない。
set @i:=0;
select @i:=@i+1 as rownum,user_id from user;
しかし、kotori::logで紹介されていた方法を用いれば、1回のSQL文で付加することができる。メモメモ。
select @i:=@i+1 as rownum,user_id from (select @i:=0) as dummy,user;
なるほど。サブクエリでユーザー変数を初期化しているのね。
で、ふとorder by節で並び替えた時の挙動が気になったので、早速試してみた。
全部で4つ試していて、始めの2つがテーブルのidカラムで並び替え(昇順、降順)、残りの2つ(3つ目と4つ目)が生成したrownumで並び替えたものである。
1つ目。
mysql> select @i := @i + 1 rownum, id
-> from (select @i := 0) dummy, tablename
-> order by id asc;
+--------+----+
| rownum | id |
+--------+----+
| 1 | 2 |
| 2 | 3 |
| 3 | 5 |
| 4 | 7 |
| 5 | 11 |
+--------+----+
5 rows in set (0.00 sec)
2つ目。
mysql> select @i := @i + 1 rownum, id
-> from (select @i:= 0) dummy, tablename
-> order by id desc;
+--------+----+
| rownum | id |
+--------+----+
| 1 | 11 |
| 2 | 7 |
| 3 | 5 |
| 4 | 3 |
| 5 | 2 |
+--------+----+
5 rows in set (0.00 sec)
3つ目
mysql> select @i := @i + 1 rownum, id
-> from (select @i := 0) dummy, tablename
-> order by rownum asc;
+--------+----+
| rownum | id |
+--------+----+
| 1 | 2 |
| 2 | 3 |
| 3 | 5 |
| 4 | 7 |
| 5 | 11 |
+--------+----+
5 rows in set (0.00 sec)
4つ目
mysql> select @i := @i + 1 rownum, id
-> from (select @i := 0) dummy, tablename
-> order by rownum desc;
+--------+----+
| rownum | id |
+--------+----+
| 5 | 11 |
| 4 | 7 |
| 3 | 5 |
| 2 | 3 |
| 1 | 2 |
+--------+----+
5 rows in set (0.00 sec)
う~ん。2つ目のSQL文の結果が予想していた結果と異なっている。予想していた結果は4つ目のSQL文と同様の結果だったのだけれど……。
Oracleで以下のようなSQL文を書いて確認してみたが、どちらも4つ目と同じ結果。
select rownum, id from tablename order by id desc;
select rownum, id from tablename order by rownum desc;
となると2つ目のSQL文は、4つ目のSQLと比べて
@i := @i + 1 rownum
を評価するタイミングが違うということになる。
2つ目のSQL文では、idカラムで並び替えた後に評価されているように見える。
というわけで調べてみたところ、MySQLのサイトの8.4. ユーザによって定義された変数のページで以下のような説明が。
ユーザ変数の評価順序は定義されておらず、与えられたクエリ内の要素に基づいて変更されることがあります。
SELECT @a, @a := @a+1 ...
では、MySQLは@a
を先に評価し次に割り当てが実行されるように見えますが、クエリの変更(例えばGROUP BY
、HAVING
またはORDER BY
節による変更)は評価順序を変更する可能性があります。
このエントリで紹介したrownumもどきは、使用する時に注意が必要ですな。
| 固定リンク
この記事へのコメントは終了しました。
コメント