MySQL 意外と簡単!グループ連番を検索結果に付番する方法!
特に連番がないテーブルに意図的に連番を振りたいってこと、日々の運用で結構あったりませんか?以外と簡単にSQLでそれを実現できます!!!
サンプルデータについて
例えば以下のようなテーブルがあり、これを題材にやってみたいと思います
mysql> DESC login ; +---------+------------+------+-----+-------------------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+------------+------+-----+-------------------+-------+ | userId | bigint(20) | NO | PRI | NULL | | | loginAt | datetime | NO | PRI | CURRENT_TIMESTAMP | | +---------+------------+------+-----+-------------------+-------+
で、以下のようなデータが入っているものとします。ユーザーIDは、1,2,3とあり、それぞれログインの間隔が異なるものとします。 loginAtはログインした日付がはいっており、useridと、loginAtのセットで、primaryキーだとします。 つまり、同じユーザーidで複数、ログイン日付が入っていると想像してください
mysql> SELECT * FROM login ; +--------+---------------------+ | userId | loginAt | +--------+---------------------+ | 1 | 2018-03-08 14:56:33 | | 1 | 2018-03-08 14:56:51 | | 1 | 2018-03-08 14:57:07 | | 1 | 2018-03-08 15:01:12 | | 1 | 2018-03-08 15:05:13 | | 1 | 2018-03-08 15:05:22 | | 1 | 2018-03-08 15:07:17 | | 1 | 2018-03-08 15:16:30 | | 1 | 2018-03-08 15:58:03 | | 2 | 2018-03-08 15:01:33 | | 2 | 2018-03-08 15:01:51 | | 2 | 2018-03-08 15:02:07 | | 2 | 2018-03-08 15:06:12 | | 2 | 2018-03-08 15:10:13 | | 2 | 2018-03-08 15:10:22 | | 2 | 2018-03-08 15:12:17 | | 2 | 2018-03-08 15:21:30 | | 2 | 2018-03-08 16:03:03 | | 3 | 2018-03-08 15:11:33 | | 3 | 2018-03-08 15:11:51 | | 3 | 2018-03-08 15:12:07 | | 3 | 2018-03-08 15:16:12 | | 3 | 2018-03-08 15:20:13 | | 3 | 2018-03-08 15:20:22 | | 3 | 2018-03-08 15:22:17 | | 3 | 2018-03-08 15:31:30 | | 3 | 2018-03-08 16:13:03 | +--------+---------------------+
やりたいこと
useridでグループ化し、それぞれに連番をふる必要が発生するのです
SQL
上記を実現するSQLは以下のようになります、なお、説明をわかりやすくする為に、下記のようなSQLでsum_loginというテーブルを作成しました(CREATE ... SELECT) ですね。
SET @no:=0; SET @userId:=null; CREATE TABLE sum_login SELECT *, IF(@userId != userId, @no:=1, @no:=@no+1) AS no, @userId:=userId AS grp_userid FROM login ORDER BY userId,loginAt ;
上記でのポイントをいくつか説明しますと
noと、useridを変数化
SET @no:=0; SET @userId:=null;
上記を変数かして、下に書いてある、ブレーク条件に利用します
前回読み込んだ、useridが異なっていたら、noのループをブレーク(break)する条件文
noは、userid毎に付番したいので、このように、noのブレイク条件を記載します
IF(@userId != userId, @no:=1, @no:=@no+1) AS no
です。では早速実行結果を確認してみます。以下のようなデータになりました。noが、useridごとに連番になっているのがわかるかと思います
+--------+---------------------+------+------------+ | userId | loginAt | no | grp_userid | +--------+---------------------+------+------------+ | 1 | 2018-03-08 14:56:33 | 1 | 1 | | 1 | 2018-03-08 14:56:51 | 2 | 1 | | 1 | 2018-03-08 14:57:07 | 3 | 1 | | 1 | 2018-03-08 15:01:12 | 4 | 1 | | 1 | 2018-03-08 15:05:13 | 5 | 1 | | 1 | 2018-03-08 15:05:22 | 6 | 1 | | 1 | 2018-03-08 15:07:17 | 7 | 1 | | 1 | 2018-03-08 15:16:30 | 8 | 1 | | 1 | 2018-03-08 15:58:03 | 9 | 1 | | 2 | 2018-03-08 15:01:33 | 1 | 2 | | 2 | 2018-03-08 15:01:51 | 2 | 2 | | 2 | 2018-03-08 15:02:07 | 3 | 2 | | 2 | 2018-03-08 15:06:12 | 4 | 2 | | 2 | 2018-03-08 15:10:13 | 5 | 2 | | 2 | 2018-03-08 15:10:22 | 6 | 2 | | 2 | 2018-03-08 15:12:17 | 7 | 2 | | 2 | 2018-03-08 15:21:30 | 8 | 2 | | 2 | 2018-03-08 16:03:03 | 9 | 2 | | 3 | 2018-03-08 15:11:33 | 1 | 3 | | 3 | 2018-03-08 15:11:51 | 2 | 3 | | 3 | 2018-03-08 15:12:07 | 3 | 3 | | 3 | 2018-03-08 15:16:12 | 4 | 3 | | 3 | 2018-03-08 15:20:13 | 5 | 3 | | 3 | 2018-03-08 15:20:22 | 6 | 3 | | 3 | 2018-03-08 15:22:17 | 7 | 3 | | 3 | 2018-03-08 15:31:30 | 8 | 3 | | 3 | 2018-03-08 16:13:03 | 9 | 3 | +--------+---------------------+------+------------+
おまけ
グループのキーが複数存在するレコードをグループ連番したい時って結構あると思います。今回説明したキーは。useridがグループ単位だったのですがuserid と busyo_code をグループ単位で連番したい時は、どうすればいいでしょうか? 答えは、簡単です、userid と busyo_code をくっつけちゃえばいいんです!!!
SET @no:=0; SET @KEY:=null; SELECT *, IF(@KEY != TRIM(userid) || TRIM(busyo_code) , @no:=1, @no:=@no+1) AS no, @KEY:=TRIM(userid) || TRIM(busyo_code) AS grp_key FROM login ORDER BY userId,busyo_code,loginAt ;