トップへ(mam-mam.net/)

MariaDB(MySQL)でテーブルから更新日が新しいレコードのみ取得

検索:

MariaDB(MySQL)でテーブルから更新日が新しいレコードのみ取得する方法を具体的SQLで解説

例えば履歴テーブルからユーザー毎にの更新日が最も新しいレコードのみ取得するSQLを作ってみます。
この例では「ユーザー(tm_user)」テーブル、「好みの履歴(t_user_favorite)」テーブルを作成して解説します。

テスト用データベースとテーブルの作成

説明のためにテスト用データベースとテーブル構造の作成です。

-- データベース作成
CREATE DATABASE IF NOT EXISTS db_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE db_test;
-- テーブル作成
CREATE TABLE tm_user(user_id SERIAL, user_name VARCHAR(20));
CREATE TABLE t_user_favorite(favorite_id SERIAL, user_id INT, favorite VARCHAR(100), up_date DATETIME DEFAULT NOW() ON UPDATE NOW());

-- テーブル構造の確認
DESC tm_user;
+-----------+---------------------+------+-----+---------+----------------+
| Field     | Type                | Null | Key | Default | Extra          |
+-----------+---------------------+------+-----+---------+----------------+
| user_id   | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| user_name | varchar(20)         | YES  |     | NULL    |                |
+-----------+---------------------+------+-----+---------+----------------+
DESC t_user_favorite;
+-------------+---------------------+------+-----+---------------------+-------------------------------+
| Field       | Type                | Null | Key | Default             | Extra                         |
+-------------+---------------------+------+-----+---------------------+-------------------------------+
| favorite_id | bigint(20) unsigned | NO   | PRI | NULL                | auto_increment                |
| user_id     | int(11)             | YES  |     | NULL                |                               |
| favorite    | varchar(100)        | YES  |     | NULL                |                               |
| up_date     | datetime            | YES  |     | current_timestamp() | on update current_timestamp() |
+-------------+---------------------+------+-----+---------------------+-------------------------------+

レコードの挿入

テスト用テーブルにレコードを挿入します。

INSERT INTO tm_user(user_name) values('森'),('佐藤'),('仮屋崎');
SELECT * FROM tm_user;
+---------+-----------+
| user_id | user_name |
+---------+-----------+
|       1 | 森        |
|       2 | 佐藤      |
|       3 | 仮屋崎    |
+---------+-----------+

INSERT INTO t_user_favorite(user_id, favorite, up_date) values(1, '納豆', '2024-01-01');
INSERT INTO t_user_favorite(user_id, favorite, up_date) values(1, '餃子', '2024-02-01');
INSERT INTO t_user_favorite(user_id, favorite, up_date) values(3, 'りんご', '2024-01-01');
INSERT INTO t_user_favorite(user_id, favorite, up_date) values(3, 'ぶどう', '2024-02-01');
INSERT INTO t_user_favorite(user_id, favorite, up_date) values(3, 'みかん', '2024-03-01');
SELECT * FROM t_user_favorite;
+-------------+---------+-----------+---------------------+
| favorite_id | user_id | favorite  | up_date             |
+-------------+---------+-----------+---------------------+
|           1 |       1 | 納豆      | 2024-01-01 00:00:00 |
|           2 |       1 | 餃子      | 2024-02-01 00:00:00 |
|           3 |       3 | りんご    | 2024-01-01 00:00:00 |
|           4 |       3 | ぶどう    | 2024-02-01 00:00:00 |
|           5 |       3 | みかん    | 2024-03-01 00:00:00 |
+-------------+---------+-----------+---------------------+

SQLの作成

1.ユーザー毎の更新日の一覧を取得

「好みの履歴(t_user_favorite)」テーブルからユーザー毎の更新日の一覧を取得するSQLは簡単で以下の通りです。

SELECT user_id, MAX(up_date) max_date FROM t_user_favorite GROUP BY user_id;
+---------+---------------------+
| user_id | max_date            |
+---------+---------------------+
|       1 | 2024-02-01 00:00:00 |
|       3 | 2024-03-01 00:00:00 |
+---------+---------------------+

2.「好みの履歴」テーブルと上記1.をジョインする

「好みの履歴(t_user_favorite)」テーブルと上記1.をジョイン(INNER JOIN)します。

SELECT t_user_favorite.user_id, t_user_favorite.favorite
FROM t_user_favorite
INNER JOIN 
  (SELECT user_id, MAX(up_date) max_date FROM t_user_favorite GROUP BY user_id) t_ufmax
ON t_ufmax.user_id = t_user_favorite.user_id AND t_ufmax.max_date = t_user_favorite.up_date;
+---------+-----------+
| user_id | favorite  |
+---------+-----------+
|       1 | 餃子      |
|       3 | みかん    |
+---------+-----------+

3.「ユーザー」テーブルと上記2.をジョインする

「ユーザー(tm_user)」テーブルと上記2.をジョイン(LEFT JOIN)します。

SELECT tm_user.user_id,tm_user.user_name, IFNULL(t_uf.favorite,'') favorite
FROM tm_user
LEFT JOIN
  (
    SELECT t_user_favorite.user_id, t_user_favorite.favorite
    FROM t_user_favorite
    INNER JOIN 
      (SELECT user_id, MAX(up_date) max_date FROM t_user_favorite GROUP BY user_id) t_ufmax
    ON t_ufmax.user_id = t_user_favorite.user_id AND t_ufmax.max_date = t_user_favorite.up_date
  ) t_uf
ON t_uf.user_id = tm_user.user_id;
+---------+-----------+-----------+
| user_id | user_name | favorite  |
+---------+-----------+-----------+
|       1 | 森        | 餃子      |
|       2 | 佐藤      |           |
|       3 | 仮屋崎    | みかん    |
+---------+-----------+-----------+

ER図は以下のようになります。

tm_user
user_id
user_name
─────→
t_user_favorite
user_id
up_date
favorite
─────
─────
t_user_favorite
user_id
MAX(up_date)
 

MariaDB(MySQL)のサンプルSQL一覧に戻る