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

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

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

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

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

4回答

3464閲覧

MYSQLのGROUP BY で思ったような取得ができない

natlpush

総合スコア32

MySQL

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

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2016/12/06 02:07

PHP+MYSQLで、思ったような結果を得ることができません。
お力添え、よろしくお願いいたします。

内容

以下のようなテーブルがあるとします。

イメージ説明

SELECT A.date , A.hour , A.category , B.name , C.content FROM ( A LEFT JOIN B ON A.member_id=B.id ) LEFT JOIN C ON B.id=C.member_id ORDER BY A.hour,B.name,C.checkorder DESC,C.ID DESC

上のようなSQL文を書くと、

イメージ説明(結果1)

となります。欲しい情報は、

12/10

13:00 basic

中野 イケメン

神田 未婚

14:00 beginner

大久保 男性

という感じで、hourで最初にヒットしたnameのC.IDの最大でcheckorderを優先した値が欲しいです。各hourにnameが重複するのを防ぎたいです。

GROUP BY を使おうと思い、

SELECT A.date , A.hour , A.category , B.name , C.content FROM ( A LEFT JOIN B ON A.member_id=B.id ) LEFT JOIN C ON B.id=C.member_id GROUP BY name ORDER BY A.hour,B.name,C.checkorder DESC,C.ID DESC

としましたが、
イメージ説明

となってしまいます。

そもそもGROUP BYの使い方が悪いのかもしれませんが、結果1のようにソートして各nameの最初のデータのみ表示するにはどのようにすれば良いでしょうか。実際には別のデータを使っているのですが、C.idでソートを変えたりもできず困っております。

よろしくお願いいたします。

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

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

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

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

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

himakuma

2016/12/06 04:23

checkorderはフラグですか?それとも2以上もありうる?
natlpush

2016/12/06 04:26

ありがとうございます。checkorderはフラグです。0か1のみです。
himakuma

2016/12/06 04:27

「hourで最初にヒットしたnameのC.IDの最大」とありますが、dateもですよね?
A.Ichi

2016/12/06 04:29

14:00の神田さんはオミットでしょうか?
natlpush

2016/12/06 04:38

>himakumaさん dateは、WHEREで本日で絞り込みたいと思っています。本日該当のメンバーの情報のみが取得したいです。
natlpush

2016/12/06 04:39

A.Ichiさん、14:00の神田さんはオミットです。nameは1つだけで、hourの早い方に表示させて終わりです。
guest

回答4

0

ベストアンサー

無理やりやるなら以下のような感じでしょうか。
※Cテーブルは、最初にmember_idごとの最大のcheckorderを調べてから、それに対応するcontentをjoinしています。
※Aテーブルも本来はCテーブルのように、member_idごとに日付が小さいものを調べてやる必要があると思いますが割愛...

sql

1SELECT A.date , A.hour , A.category , B.name , C.content 2FROM ( 3 SELECT * FROM A GROUP BY member_id) A 4 LEFT JOIN B ON A.member_id=B.id 5 LEFT JOIN ( 6 SELECT gc.* FROM ( 7 SELECT member_id, max(checkorder) checkorder FROM C GROUP BY member_id) mc 8 INNER JOIN (SELECT * FROM C GROUP BY member_id, checkorder) gc 9 ON mc.checkorder = gc.checkorder and mc.member_id = gc.member_id 10 ) C ON B.id=C.member_id;

SQLが複雑になっているのは、そもそもテーブル設計がおかしいからかもしれません...

投稿2016/12/06 04:27

popobot

総合スコア6586

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

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

popobot

2016/12/06 04:43 編集

少し制約を加えればもっとシンプルになると思いました。 例えば、各member_idに対してcheckorder=1のものは1レコードしかないのであれば、BテーブルとCテーブルを単にjoinして、where checkorder = 1とすればいいだけとか もしくは、checkorderカラムをやめて、Bテーブルにc_idカラムを追加して、Cテーブルのうち優先するIDをc_idに格納しておくとjoinがとてもかんたんになります。
natlpush

2016/12/06 05:11

ありがとうございます。 ご提示いただいたSQLで、得たい情報を得ることができました。 ただ私のレベルではSQL文を理解することができないので、一つずつ調べていく必要がありそうです。 できればシンプルにいきたいのですが、そもそもどの辺に無理がありますか? それすらもわからないので、申し訳ありません。
popobot

2016/12/06 05:18

> ただ私のレベルではSQL文を理解することができないので、一つずつ調べていく必要がありそうです。 SQLは個々の括弧ごとに分解して実行すれば、それぞれ何をやっているかわかると思いますよ > できればシンプルにいきたいのですが、そもそもどの辺に無理がありますか? 一つ上のコメントに書いてとおりですが... よくわからなければ聞いてください。 あと、最終的にPHPで使うのであれば、無理に一つのSQLで取得しないで、PHP側で処理するでもいいと思いますよ!
natlpush

2016/12/06 05:28

ありがとうございます。 そうですよね。 すべての項目について、おっしゃる通りだと思います。 素晴らしい回答、ありがとうございます!!
himakuma

2016/12/06 05:49

私もテーブル設計を間違っていると思います。
guest

0

回答ではありませんが、テーブル設計を正規化の手順 の第3正規化までやって見直した方が良いです。たぶんきちんとテーブル設計できる人の力を借りた方が良いでしょう。
回答してくれた人のSQLを見てわかると思いますが、テーブル設計が悪いとSQLが複雑になってパフォーマンスも落ちるし、メンテナンスが難しくなります。大手Slerが設計したDBでテーブル設計が変なため、二重三重のインラインビューを使ったり、副問合せの多用、どうしてもPL/SQLまで使ってLOOPさせないとリストを出せない環境のお客様で作業したことがあります。悪いテーブル設計は負の遺産です。

投稿2016/12/06 09:02

Orlofsky

総合スコア16415

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

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

0

  • テーブル作成

SQL

1create table tbl_a(dt datetime,category varchar(20),member_id int); 2insert into tbl_a values('2016-12-10 13:00','basic',1),('2016-12-10 13:00','basic',2),('2016-12-10 14:00','beginner',2),('2016-12-10 14:00','beginner',3); 3create table tbl_b(ID int,name varchar(20)); 4insert into tbl_b values(1,'中野'),(2,'神田'),(3,'大久保'); 5create table tbl_c(ID int,member_id int,content varchar(20),checkorder tinyint); 6insert into tbl_c values(1,3,'男性',1),(2,3,'未婚',0),(3,2,'未婚',0),(4,1,'既婚',0),(5,1,'イケメン',0);
  • テーブルA表示

SQL

1select dt,category,member_id 2 from tbl_a where (dt,member_id ) in 3(select min(dt),member_id from tbl_a group by member_id); 4
  • テーブルB表示

SQL

1select * from tbl_b;
  • テーブルC表示

SQL

1select member_id,content from tbl_c 2where ID in( 3select max(ID) 4from tbl_c 5where (member_id,checkorder) in( 6select member_id,max(checkorder) from tbl_c group by member_id 7) 8group by member_id 9);

構造的に一番簡単なテーブルBにリレーションして

SQL

1select dt,category,name,content 2from tbl_b as t1 3inner join ( 4select dt,category,member_id 5 from tbl_a where (dt,member_id ) in 6(select min(dt),member_id from tbl_a group by member_id) 7) as t2 on t1.ID=t2.member_id 8inner join ( 9select member_id,content from tbl_c 10where ID in( 11select max(ID) 12from tbl_c 13where (member_id,checkorder) in( 14select member_id,max(checkorder) from tbl_c group by member_id 15) 16group by member_id 17) 18) as t3 on t1.ID=t3.member_id; 19

投稿2016/12/06 05:27

yambejp

総合スコア114583

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

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

0

無理やりですが

sql

1create table a_tbl (adate text, ahour text, category text, member_cd int); 2create table b_tbl (id int, name text); 3create table c_tbl (id int, member_id int, comment text, checkorder int); 4 5select t9.adate as date, t9.ahour as hour, t9.category, t8.name, t7.comment from a_tbl t9 6join 7(select t5.adate, min(t5.ahour) as ahour, t5.member_id, t6.comment, t5.category from a_tbl t5 8 join ( select * from c_tbl t3 join (select t1.member_id, max(id) as id from c_tbl t1 9 join (select member_id, max(checkorder) as checkorder from c_tbl group by member_id) t2 10 using(member_id,checkorder) group by 1) t4 11 using(member_id,id)) t6 using (member_id) group by t5.member_id) t7 12using(adate,ahour,member_id) 13join b_tbl t8 on t8.id=t7.member_id;

投稿2016/12/06 04:57

編集2016/12/06 05:13
A.Ichi

総合スコア4070

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問