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

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

新規登録して質問してみよう
ただいま回答率
85.48%
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回答

22143閲覧

並べ替え後にある要素でGROUP BYし、その要素のそれぞれ1つ目を取得したい

takushi168

総合スコア228

MySQL

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

SQL

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

2グッド

0クリップ

投稿2016/07/01 05:41

編集2016/07/01 08:50

…と言葉で書くととても分かりにくいのですが。

<追記>
全体的に加筆修正しました。

【環境】
MySQL(5.6)

【やりたいこと】
まず、data_table テーブルに foobar のカラムがあり、
以下のようにデータが入っているとします。
buz その他のデータも入っています。
PKは foobar の複合です。

------
foo bar buz
------
A 1 aaa
B 1 bbb
B 2 ccc
C 1 ddd
C 2 eee
------

このテーブルから、
fooの値(A,B,C)それぞれについて、
barが2であるレコード(なければ1であるレコード)」
を取得したいのです。
(また、ここでは1と2のうち2を優先して取る例としていますが、1と3のうち1を優先して取る、等の可能性もあります。
そのあたりはアプリケーション側で制御します。クエリの書き換えもある程度可能です。)

このような状態ですね。
------
foo bar buz
------
A 1 aaa
B 2 ccc
C 2 eee
------

現在のところ、
以下のようなクエリで一応は望むものが取得できているのですが
動作は保証されない書き方のはずです。

sql

1SELECT 2 `dt`.`foo`, `dt`.`bar`, `dt`.`buz` 3FROM 4 ( 5 SELECT `foo`, `bar`, `buz` 6 FROM `data_table` 7 ORDER BY `foo` ASC, `bar` = 2 DESC, `bar` = 1 DESC 8 ) AS `dt` 9GROUP BY `dt`.`foo`

これを改良するか、もしくは全く別の形でも構わないのですが、
正しい書き方はありますでしょうか?


<追記>
ご回答いただいた内容を参考にさせていただき、以下の形に落ち着きそうです。
(ちょっと長ったらしいですが、実装上の諸々の都合があり…。)

sql

1SELECT `data_table`.`foo`, `data_table`.`bar`, `data_table`.`buz` 2FROM `data_table` 3INNER JOIN 4 ( 5 -- ここの「MAX」をアプリ側で「MIN」に書き変える場合アリ 6 SELECT `foo`, MAX(`bar`) AS `bar` 7 FROM `data_table` 8 WHERE `bar` IN (1,2) 9 GROUP BY `foo` 10 ) AS `dt_sub` 11 ON `data_table`.`foo` = `dt_sub`.`foo` 12 AND `data_table`.`bar` = `dt_sub`.`bar`
KiyoshiMotoki, mooey👍を押しています

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

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

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

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

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

guest

回答4

0

ベストアンサー

fooでグループにし、barの最大値を求めるクエリがこうです。

SQL

1SELECT foo, MAX(bar) FROM data_table GROUP BY foo

そして、それをサブクエリとして使い、該当するfoo、barのレコードをWHEREで絞り込めばできあがりです。

SQL

1SELECT * FROM data_table 2WHERE (foo, bar) IN ( 3 SELECT foo, MAX(bar) FROM data_table GROUP BY foo 4);

###追記
質問文の条件「1を優先する場合もある」を見落としていました…このやり方はだめですね

###追記の追記
悔しかったので優先度テーブルも考慮したやりかたを書いておきます。
http://sqlfiddle.com/#!9/dce432/1

SQL

1/*優先度テーブル*/ 2/*1と2なら2のほうが優先度が高いが、1と3なら1のほうが優先度が高い*/ 3CREATE TABLE bar_priority(bar INT PRIMARY KEY, priority INT); 4INSERT INTO bar_priority 5VALUES 6(1, 10), 7(2, 15), 8(3, 5); 9 10SELECT foo, bar, buz FROM data_table 11LEFT JOIN bar_priority USING(bar) 12WHERE (foo, priority) IN ( 13 SELECT foo, MAX(priority) FROM data_table 14 LEFT JOIN bar_priority USING(bar) 15 GROUP BY foo 16 );

投稿2016/07/01 06:30

編集2016/07/01 06:48
masaya_ohashi

総合スコア9206

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

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

takushi168

2016/07/01 06:33

ありがとうございます。助かります。 なるほど、IN句でも良いですね。 こちらも検討させていただきます。
takushi168

2016/07/01 06:38

>「1を優先する場合もある」を見落としていました… あ、アプリケーション側(PHP)でMINかMAXかの切り替えはできるので、そこまで大きい問題ではありません。 (もちろん、結構格好悪い書き方にはなりますが…)
takushi168

2016/07/01 07:08

なるほど! 優先度を持つのは良いかもしれません。 こちらも検討いたします。ありがとうございます。
KiyoshiMotoki

2016/07/01 07:41 編集

横から失礼します。 honey8823様 選択肢が > 1と2のうち2を優先 または > 1と3のうち1を優先 などの2択だけであれば、 > アプリケーション側(PHP)でMINかMAXかの切り替え が、もっとも簡単な"手"だと思います。 もし、 「1と2と3のうち 2, 1, 3 の順で優先」 などのように選択肢が3つ以上になりえるのであれば、 masaya_ohashi様の回答にあるように優先度テーブルを設ける、など別の方法が必要になりますね。
takushi168

2016/07/01 08:51

ありがとうございます! 常に二択ではあるので、MIN/MAXをアプリ側で切り替える手法で一旦決着としました。 (質問本文にも追記いたしました) 本当に助かりました。 まとめてのお礼ですみませんが、皆様ありがとうございます。
guest

0

sql

1SELECT dt.* FROM data_table AS dt INNER JOIN ( 2 SELECT foo, MAX(bar) bar FROM data_table WHERE bar IN (1, 2) GROUP BY foo 3) AS tmp ON dt.foo = tmp.foo AND dt.bar = tmp.bar;

http://sqlfiddle.com/#!9/02d24/8

投稿2016/07/01 06:21

KiyoshiMotoki

総合スコア4791

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

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

takushi168

2016/07/01 06:32

ありがとうございます! 確かにきちんと取れました。 レコード数が多めになる見込みのテーブルなので 速度検証等も行いつつ検討させていただきます。
guest

0

今の条件だけだと、barが1か2のデータを拾ってmaxを取ればよいような・・・

sql

1select foo,max(bar) as bar from data_table 2where bar in (1,2) 3group by foo

投稿2016/07/01 05:54

yambejp

総合スコア114829

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

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

takushi168

2016/07/01 06:02

ありがとうございます。 申し訳ありません、ご指摘のとおり、今の条件だとそうなりますね…お恥ずかしい。 本文にも追記しましたが、 foo,bar以外のカラムが存在する可能性があるため、MAX値ではなくレコードとして取得したいです。
yambejp

2016/07/01 06:33

新しい条件だとこうですね select * from data_table where (foo,bar) in( select foo,max(bar) from data_table where bar in (1,2) group by foo)
guest

0

sql

1SELECT 2 foo, max(bar) as bar 3FROM `data_table` 4WHERE bar IN (1, 2) -- 1、2しか持ち得ないなら不要 5GROUP BY foo

投稿2016/07/01 05:51

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

takushi168

2016/07/01 06:02

早速のご回答ありがとうございます。 申し訳ありません…本文にも追記しましたが、 foo,bar以外のカラムが存在する可能性があるため、MAX値ではなくレコードとして取得したいです。 (このクエリを利用して、紐付くレコードを取得することはできそうなので、その方法も考えてみます)
退会済みユーザー

退会済みユーザー

2016/07/01 06:03

SELECT max(bar) as bar , * FROM `data_table` フィールドを列挙すればいいだけでは?
退会済みユーザー

退会済みユーザー

2016/07/01 06:12

ああ、そうか。プライマリーキーを持っているのかとかその辺の情報必要ですね。
takushi168

2016/07/01 06:32

すみません、確かに全然情報足りなかったですね…。 ありがとうございます。追記いたしました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問