質問するログイン新規登録
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

4回答

230閲覧

指定された日付までの日付を持つ値のうち、グループ毎に最新の値を取得したい

Auxo

総合スコア35

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

0クリップ

投稿2025/10/06 18:08

編集2025/10/07 03:19

0

0

実現したいこと

次のようなデータがある場合

idgroup_idvalue_numberregisted
11112025-08-01
22212025-08-01
31122025-10-01
41132025-08-01
51142025-08-01
62222025-09-01

id:6のregistedを「2025-10-01」から「2025-09-01」に修正しました。

指定された日付までの登録データの中で、グループ毎に最新の値が取得したいです。
同一のグループで同一の日付に複数の登録がある場合は、後から登録されたもの(idが大きいもの)を取得したいと考えています。
なお、登録は必ずしも日付順ではない為、idの大きいなものにより古い日付のデータが登録される事もあります。

日付の閾値として「2025-10-01」が指定された場合は以下のような結果を期待します。

idgroup_idvalue_numberregisted
31122025-10-01
62222025-09-01

id:6の内容修正に伴い期待する取得結果も修正しました

日付の閾値として「2025-08-01」が指定された場合は以下のような結果を期待すます。

idgroup_idvalue_numberregisted
51142025-08-01
22212025-08-01

このような結果を期待していますが、うまく取得する方法が思いつきません。

発生している問題・分からないこと

SQLだけで結果を取得する事が難しい場合は、諦めて一度全件取得しプログラム側の個別の集計処理も考えています。

何か良い方法はありますでしょうか。

試したこと・調べたこと

  • teratailやGoogle等で検索した
上記の詳細・結果

多くの場合で、登録されるデータとして必ず新しいものが後に登録される(idが大きい)ケースはあり、参考になるのですが、今回のように必ずしもidが大きなものが新しい日付でない場合は上手く取得できませんでした。

試したSQL(微妙に上手くいっていないケース)

SQL

1SELECT 2`group_id`, 3`id`, 4MAX(registed) AS `latestDate` 5FROM 6`hoge` 7WHERE 8`registed` <= '2025-08-01' 9GROUP BY 10`group_id` 11;

これですと2つ目のケースのグループ2が正常に新しいレコードが取得できません。
なお、MySQLでのSTRICT制約は外しています。

補足1

元データの id:6の内容修正に伴い期待する取得結果も修正しました。
閾値として設定された日付より前に登録されたデータの内、より後に登録されたものを取得したい為。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shiketa

2025/10/07 02:14 編集

読み違えていました。取り下げます。
Auxo

2025/10/07 02:15 編集

質問ありがとうございます。 >「日付の閾値として「2025-10-01」が指定された場合」には、2025-10-01が含まれ、 >「日付の閾値として「2025-09-01」が指定された場合」には、2025-09-01は含まないのですね? 2つ目のケースは私の閾値の指定間違いでした。 「2025-09-01」ではなく「2025-08-01」でした。 間違った表記となってしまい申し訳ございませんでした。 閾値となっている日付は、その値の有効な日付です。 履歴を持ちたいので「上書き」ではなく「追加」としています。 本来であれば「日付」ではなく「日時」として時間も管理すべきなのですが、 値の受付(入力)が日付単位の為、値の受け入れとしては単純に後勝ち方式となっています。 そのため、どうにも閾値である日付が同日となっているケースでより新しいものを上手く撮れないという状況です。
jimbe

2025/10/07 02:33

既存回答のコメントに「微妙にうまくいかないSQL」を提示されていますが、それらは質問本文("試したこと")に結果(欲しい結果と比較し易い形で)と共に書いて置いたほうが良いのではないでしょうか。
shiketa

2025/10/07 03:04

「日付の閾値として「2025-10-01」が指定された場合は以下のような結果を期待し」ているのであれば、わかる気がしますが、なぜid=3が選択されるのかが理解できていません。 |--|--------|------------|--------| |5|1|14|2025-08-01| |6|2|22|2025-09-01| なにか大事な要件を読み取れていないのでしょうね。わたしが。
Auxo

2025/10/07 03:22 編集

id=5ではなくid=3が選択される理由は、閾値の範囲内(2025-10-01以前なので「<=」)である場合は、第一条件としては日付(registed)がより新しいものが選択されるイメージです。 その上でもし同一の日付を持つものが複数ある場合は、第二条件としてより後に登録されたデータ(idが大きなもの)が選択されるイメージでおります。 閾値に対する判定(「以前」として判断)を明示的にしていませんでした。 失礼いたしました。
guest

回答4

0

ウィンドウ関数が利用可能なバージョン・環境であれば、ROW_NUMBER関数を使う方法が最も分かりやすいと思います。

sql

1SELECT id, group_id, value_number, registed 2FROM ( 3 SELECT 4 id, group_id, value_number, registed, 5 ROW_NUMBER() OVER (PARTITION BY group_id ORDER BY registed DESC, id DESC) AS rn 6 FROM sample_table 7 WHERE registed <= '2025-10-01' 8) AS T 9WHERE rn = 1;

一方、ウィンドウ関数が利用できないやや古いバージョンや環境の場合は、サブクエリを利用する方法もあります。

sql

1SELECT * 2FROM sample_table AS S1 3WHERE S1.registed <= '2025-10-01' 4AND NOT EXISTS ( 5 SELECT * 6 FROM sample_table AS S2 7 WHERE S2.registed <= '2025-10-01' 8 AND S1.group_id = S2.group_id 9 AND (S1.registed, S1.id) < (S2.registed, S2.id) 10)

なお、検証に使用したDDL・DMLは以下の通りです。

sql

1CREATE TABLE sample_table ( 2 id INT PRIMARY KEY, 3 group_id INT, 4 value_number INT, 5 registed DATE 6); 7 8INSERT INTO sample_table (id, group_id, value_number, registed) VALUES 9(1, 1, 11, '2025-08-01'), 10(2, 2, 21, '2025-08-01'), 11(3, 1, 12, '2025-10-01'), 12(4, 1, 13, '2025-08-01'), 13(5, 1, 14, '2025-08-01'), 14(6, 2, 22, '2025-09-01');

投稿2025/10/07 04:26

neko_the_shadow

総合スコア2401

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Auxo

2025/10/07 10:32

回答ありがとうございます。 ご提示いただいた内容で無事解決いたしました。 内容をあらためて確認しつつ、勉強させていただきます。 特にウィンドウ関数はあまり使った事がないので、 良い機会なのでもう一度勉強し直したいと思います。 なお、ベストアンサーについては申し訳ございませんが、 投稿時間の早かった方に付けさせていただきました。
guest

0

ベストアンサー

postgres で試してますが、 shiketa さんの定義コードを拝借して(register textregisted date)

sql

1create table hoge ( 2 id int, 3 group_id int, 4 value_number int, 5 registed date 6); 7 8insert into hoge values 9 (1, 1, 11, '2025-08-01'), 10 (2, 2, 21, '2025-08-01'), 11 (3, 1, 12, '2025-10-01'), 12 (4, 1, 13, '2025-08-01'), 13 (5, 1, 14, '2025-08-01'), 14 (6, 2, 22, '2025-09-01');

そのまんま書いたら

sql

1SELECT c.* 2FROM hoge AS c 3JOIN (SELECT MAX(a.id) AS id 4 FROM hoge AS a 5 JOIN (SELECT group_id, MAX(registed) AS registed 6 FROM hoge 7 WHERE registed <= '2025-08-01' 8 GROUP BY group_id) AS b 9 ON a.group_id=b.group_id AND a.registed=b.registed 10 GROUP BY a.group_id, a.registed) AS d 11ON c.id=d.id
id | group_id | value_number | registed ----+----------+--------------+------------ 2 | 2 | 21 | 2025-08-01 5 | 1 | 14 | 2025-08-01 (2 行)

7行目を '2025-10-01' に変えると

id | group_id | value_number | registed ----+----------+--------------+------------ 3 | 1 | 12 | 2025-10-01 6 | 2 | 22 | 2025-09-01 (2 行)

となりますが、如何でしょう。

投稿2025/10/07 03:49

編集2025/10/07 03:57
jimbe

総合スコア13422

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Auxo

2025/10/07 10:31

回答ありがとうございます。 ご提示いただいた内容で無事解決いたしました。 内容をあらためて確認しつつ、勉強させていただきます。
guest

0

簡単にやるならこんな感じでいけると思います

SQL

1select * from tbl inner join ( 2select max(id) as id,group_id,register 3from tbl 4group by group_id,register 5having register='2025-10-01' 6) as sub using(id,group_id,register)

投稿2025/10/07 00:56

yambejp

総合スコア118145

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Auxo

2025/10/07 01:17

私の取得元データの例示が悪く、問題点がわかり難かった為、取得元データを修正しました。 例示いただいたhaving句の指定ですと、その日のデータに限定されてしまいます。 期待するものとしては、指定された日付以前の「registed」を持つレコードの中で、最新(idの大きいなもの)をグループ毎に取得できないかな、という所です。 イメージとしては「GROUP BY」を「registed」にかけて、同一だった時により後のidが選択されれば良いのですが、実際にはそういった動きにはならず、強引に先にidで降順にソートした結果をGROUP BYしたりもしましたが、やはりidの小さいものが取得されてしまうようでした。 以下、微妙に上手くいかないSQL文です。 SELECT `group_id`, `id`, MAX(registed) AS `latestDate` FROM `hoge` WHERE `registed` <= '2025-08-01' GROUP BY `group_id` ; これですと2つ目のケースのグループ2が正常に新しいレコードが取得できません。 なお、MySQLでのSTRICT制約は外しています。
yambejp

2025/10/07 01:31

新しい条件になって「最新の値」の定義があいまいです registerdの最大値でさらにその中の最大のidを取りたいのでしょうか?
Auxo

2025/10/07 10:34

>registerdの最大値でさらにその中の最大のidを取りたいのでしょうか? ご指摘のとおりです。 registedが閾値以内の条件でもっとも新しく、且つ、最大のidとなります。 なお、実現できるSQL文を無事確認する事ができました。 色々と私の提示内容が曖昧でご迷惑をおかけ致しました。 コメントありがとうございました。
guest

0

sql

1create table hoge ( 2 id int, 3 group_id int, 4 value_number int, 5 register text 6); 7 8insert into hoge values 9 (1, 1, 11, '2025-08-01'), 10 (2, 2, 21, '2025-08-01'), 11 (3, 1, 12, '2025-10-01'), 12 (4, 1, 13, '2025-08-01'), 13 (5, 1, 14, '2025-08-01'), 14 (6, 2, 22, '2025-10-01') 15; 16 17with 18aa as ( 19 select 20 group_id, 21 max(value_number) as value_number, 22 register 23 from hoge 24 group by group_id, register 25) 26, 27bb as ( 28 select hoge.* from hoge, aa 29 where hoge.group_id = aa.group_id 30 and hoge.value_number = aa.value_number 31 and hoge.register = aa.register 32) 33select * from bb 34 where register <= '2025-10-01' 35 order by 4, 1 36;

結果。

idgroup_idvalue_numberregister
22212025-08-01
51142025-08-01
31122025-10-01
62222025-10-01

「閾値」のあたりは、最後のwher節でどうにでもなるかと。

投稿2025/10/07 00:37

編集2025/10/07 00:40
shiketa

総合スコア4157

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yambejp

2025/10/07 00:57

registerはdate型を指定したよいかもしれません
Auxo

2025/10/07 01:21

やはり「GROUP BY」のような形でグループ毎に1つの結果を求める事は難しいのでしょうか。 微妙に上手くいかないSQL文として以下の様なところまでは実現できております。 SELECT `group_id`, `id`, MAX(registed) AS `latestDate` FROM `hoge` WHERE `registed` <= '2025-08-01' GROUP BY `group_id` ; この文ですと同一の「registed」を持つ場合に「id」が古いもの(小さいなid)が取得されてしまっており、それを新しいものに何とかできないかと試行錯誤しております。 試しに、SORTで降順にした結果に対して実行してみましたが、結果は変わりませんでした。
shiketa

2025/10/07 02:06

> registerはdate型を指定したよいかもしれません はい。手抜きです f(^^;
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問