Database JUNKY

MySQL,MariaDBを中心としたブログです

MySQL 意外と簡単!グループ連番を検索結果に付番する方法!

特に連番がないテーブルに意図的に連番を振りたいってこと、日々の運用で結構あったりませんか?以外と簡単にSQLでそれを実現できます!!!

f:id:hit10231023:20180309104332j:plain

サンプルデータについて

例えば以下のようなテーブルがあり、これを題材にやってみたいと思います

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
;