質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.47%
MySQL

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

Q&A

解決済

6回答

22369閲覧

MySQLでグループ毎に最新の情報を習得したい

noripi

総合スコア34

MySQL

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

1グッド

4クリップ

投稿2016/04/01 06:46

MySQL5.5で下記の商品データベースから、各商品ID毎の最新情報を取得したいです。
《product》
| product_id | price shop_id | shop_id | modified |
| 1 | 100 | 001 | 2016-03-30 14:00|
| 1 | 148 | 015 | 2016-03-30 15:00|
| 2 | 254 | 001 | 2016-02-26 14:31|
| 2 | 384 | 022 | 2016-03-31 13:50|
| 2 | 482 | 016 | 2016-01-24 10:00|
| 3 | 851 | 015 | 2016-03-30 14:00|
| 3 | 650 | 022 | 2016-03-14 16:00|
| 3 | 500 | 016 | 2016-03-26 14:30|

《結果》
| product_id | price shop_id | shop_id | modified |
| 1 | 148 | 015 | 2016-03-30 15:00|
| 2 | 384 | 022 | 2016-03-31 13:50|
| 3 | 851 | 015 | 2016-03-30 14:00|

また、実際のDBには大量に情報があるため、できるだけ軽い処理にしたいです。
処理時間のかかるサブクエリは避けたいです。

退会済みユーザー👍を押しています

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

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

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

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

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

guest

回答6

0

ベストアンサー

以下のページが、まさに同じ問題に対する解決策を提示してくれています。
https://dev.mysql.com/doc/refman/5.6/ja/example-maximum-column-group-row.html

ご質問のテーブル構造に当てはめると、以下のようになるかと思います。

■相関サブクエリ バージョン

sql

1SELECT main.* FROM product AS main WHERE modified = ( 2 SELECT MAX(modified) FROM product AS sub WHERE main.product_id = sub.product_id 3);

■非相関サブクエリ バージョン

sql

1SELECT main.* FROM product AS main 2INNER JOIN ( 3 SELECT product_id, MAX(modified) AS modified FROM product GROUP BY product_id 4) AS sub 5 ON main.product_id = sub.product_id AND main.modified = sub.modified;

■外部結合バージョン

sql

1SELECT main.* FROM product AS main 2 LEFT OUTER JOIN product AS sub ON main.product_id = sub.product_id AND main.modified < sub.modified 3WHERE sub.modified IS NULL;

ただし、

できるだけ軽い処理にしたいです。

処理時間のかかるサブクエリは避けたいです。

について、クエリの実行時間はインデックスの有無やデータの分布具合によっても変わるため、一概にサブクエリが重いとは限りません

実装しようとしているクエリの性能を確認したければ、実際にテストデータを投入したDBに流してみるのと、実行計画を確認するのがよいです。
実行計画については、以下のサイトが参考になります。
https://dev.mysql.com/doc/refman/5.6/ja/explain.html
http://nippondanji.blogspot.jp/2009/03/mysqlexplain.html

ちなみに、サブクエリにも相関サブクエリと非相関サブクエリの2種類があり、よく「重い」と言われるのは相関サブクエリの方です。

投稿2016/04/01 08:12

編集2016/04/01 08:15
KiyoshiMotoki

総合スコア4791

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

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

noripi

2016/04/01 09:22

詳しく解説していただきありがとうございます。正直サブクエリに2種類あるのはしりませんでした。勉強不足を痛感しています。 3パターン試した結果、外部結合バージョンが一番早かったです。
KiyoshiMotoki

2016/04/01 09:29

> 3パターン試した結果、外部結合バージョンが一番早かったです。 ご丁寧な報告、ありがとうございます。 お役に立てたなら幸いです。
guest

0

nabe3さんのユーザ変数を使った方法ですが、

OracleACEのAketiJyuuzouさんとyoku0825さんと
日本オラクルの木村さんによると
MySQLのユーザ変数は評価順序が未定義だそうです。
http://qiita.com/AketiJyuuzou/items/cced9b70cc714b382d98

ゆえに、結果が保証されないと思います。

投稿2016/04/01 09:04

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

noripi

2016/04/01 09:14

なるほど。勉強になります。
guest

0

JOINかEXISTSを使うべきかと

JOIN

SQL

1SELECT 2 A.* 3FROM product A 4JOIN ( 5 SELECT 6 B.product_id 7 , MAX(modified) modified 8 FROM product B 9 GROUP BY 10 B.product_id 11) C 12ON C.product_id = A.product_id 13AND C.modified = A.modified 14

EXISTS

SQL

1SELECT 2 * 3FROM procudt A 4WHERE NOT EXISTS( 5 SELECT 1 6 FROM product B 7 WHERE B.product_id = A.product_id 8 AND B.modified > A.modified 9) 10

投稿2016/04/01 07:47

kutsulog

総合スコア985

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

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

noripi

2016/04/01 09:18

ありがとうございます。試してみます。
guest

0

サブクエリ必要な気がします。
最初に各商品IDの最新日付を取得してからJOINと言う形が一般的ですね。

SQL

1SELECT p.product_id, p.price, p.shop_id, p.modified FROM product p 2INNER JOIN ( 3 SELECT product_id, MAX(modified) modified 4 FROM product 5 GROUP BY product_id 6) max_p 7ON p.product_id = max_p.product_id 8AND p.modified = max_p.modified

投稿2016/04/01 07:35

編集2016/04/01 07:36
lilithchan

総合スコア249

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

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

noripi

2016/04/01 09:17

やはりサブクエリは必要ですか。
guest

0

こちらのSQLではいかがでしょうか?

product_idごとにmodifiedの新しいもの順に1, 2, 3とナンバリングし、
No1のレコードのみを抽出します。

SQL

1SELECT t.product_id, t.price_shop_id, t.shop_id, t.modified 2FROM 3( 4 SELECT @row_num := IF(@prev_value=p.product_id,@row_num+1,1) AS RowNumber, 5 p.product_id, 6 p.price_shop_id, 7 p.shop_id, 8 p.modified, 9 @prev_value := p.product_id 10 FROM product p, 11 (SELECT @row_num := 1) x, 12 (SELECT @prev_value := 'x') y 13 ORDER BY p.product_id, p.modified DESC 14) t 15WHERE t.RowNumber = 1 16ORDER BY product_id;

投稿2016/04/01 07:21

nabe3

総合スコア345

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

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

noripi

2016/04/01 09:15

このような書き方もあるのですね。
退会済みユーザー

退会済みユーザー

2018/09/16 22:28

幸運にも期待通りの結果を得られるかもしれませんが、それが確約されないSQLで、 論外の品質なので、マイナス投票します。 http://download.nust.na/pub6/mysql/doc/refman/5.1/ja/user-variables.html >基本的なルールは、ステートメントの一部でユーザ変数値を割り当てないこと >および同一ステートメント内の他部分で同じ変数を使用しないことです。 >期待通りの結果を得られるかもしれませんが、これは確約されていません。
aiou

2019/04/06 13:54

退会済ユーザ様 減点するなら下記の2点がより適切です。 select文でのユーザ変数への値の代入は5.7で非推奨になり、8.0以降で削除予定の機能であることが1点目。 http://www.mysql.gr.jp/mysqlml/mysql/msg/16488 MySQLの開発者がブログに https://mysqlserverteam.com/row-numbering-ranking-how-to-use-less-user-variables-in-mysql-queries/ It works. But it relies on the fact that MySQL sets @rownum before setting @prev_sex, i.e. evaluates selected expressions from left to right. Which is true for this query, but not for all queries と書いてあるのが2点目。
guest

0

group by と max ですかね

sql

1select product_id, price_shop_id, shop_id, MAX(modified) as modified from product group by product_id; 2 3```な感じ? 4この問題はもしかして 5[https://teratail.com/questions/31016](https://teratail.com/questions/31016) 6と同じでは無いですか?

投稿2016/04/01 07:17

HiroshiWatanabe

総合スコア2160

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

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

nabe3

2016/04/01 07:31

price_id = 2 の期待結果が、 price shop_id = 384, shop_id = 022, modified = 2016-03-31 13:50 ですが、 単純な group by では、 price shop_id = 254, shop_id = 001, modified = 2016-03-31 13:50 を返してしまうことがあります。 group by に含まれていない price_shop_id と shop_id の値がproduct_idの 最新のmodifiedに対する値と一致しないことがあります。
HiroshiWatanabe

2016/04/01 07:46

あー…なるほど。うっかりしてました。ご指摘ありがとうございます。
noripi

2016/04/01 09:13

確かにそうですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問