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

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

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

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

JOIN

これはSQL文のJOINに関するタグです。リレーショナルデータベースシステムの二つ以上のテーブルを結合する際に、この構文が利用されます。

PHP

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

Q&A

解決済

4回答

443閲覧

left outer join について質問です。

kurofukuro

総合スコア21

MySQL

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

JOIN

これはSQL文のJOINに関するタグです。リレーショナルデータベースシステムの二つ以上のテーブルを結合する際に、この構文が利用されます。

PHP

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

0グッド

0クリップ

投稿2017/10/31 22:00

編集2017/10/31 23:57

###前提・実現したいこと
php+mysqlでウェブアプリを作っている中で、
mysql をDBのセレクト文について、はまってしまい。
質問させていただきました。
left outer join についてです。

下記のような時にA.s_id=100とAテーブルの5つを指定しているのですが、

結果が、
初心者の筆問で、うまく意図が伝わっているのかわかりませんが、レフトジョインなので、
左にならえということで、
whereでAテーブルのs_idが入った5個が抽出されると思っておりましたが結果が
共通ID(A_id)を持ったものすべてが抽出されており、困惑しております。

下記の事で、
結合して10個の結果全てに対してs_idが入って結合したものでwhereしているものと考えてよろしいでしょうか。
その時主となるテーブルAに該当するものが5個しかなくても、それよりも多く抽出しているのか不可解でご教授頂きたいです。

また、下記のような結果を取得したい場合どのように書くことができるのかご指導いただければ幸いです。
【取りたいデーター】

A_id担当者B_id
1aさん1
2bさん2
3cさん3
4dさん4
5eさん5

Aテーブルにある数のみ重複はさせたくない。

###発生している問題・エラーメッセージ

テーブル名A
|A_id|名前|年齢|s_id|
|:--|:--:|--:|
|1|Aさん|25|100|
|2|Bさん|22|100|
|3|Cさん|23|100|
|4|Dさん|22|100|
|5|Eさん|24|100|
|6|Fさん|24|200|

テーブル名B
###【訂正しました】B_idとA_idが逆に記載しておりました・・・

B_id担当者A_id
1aさん1
2bさん2
3cさん3
4dさん4
5eさん5
6fさん1
7gさん2
8hさん3
9iさん4
10jさん5

###該当のソースコード
使用したmql文
SELECT A.A_id,A.名前,B.B_id FROM A LEFT OUTER JOIN B on A.A_id = B.A_id where A.s_id = 100;

###試したこと
結果が、

A_id名前B_id
1Aさん1
2Bさん2
3Cさん3
4Dさん4
5Eさん5
1Aさん1
2Bさん2
3Cさん3
4Dさん4
5Eさん5

全部で10個がでてしまいます。
私的には、whereでAテーブルの5個を指定しているので、5個しか出ないと思っていたのですが・・・

###補足情報(言語/FW/ツール等のバージョンなど)
より詳細な情報
環境は、
php 5.6
mysql 5.6
になります。
どうぞよろしくお願いいたします。

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

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

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

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

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

guest

回答4

0

単純な話、テーブルBを絞り込む条件が足りないからです。
B_idがかぶった場合、最も小さなA_idを選ぶという条件を追加すればすんなりでます
(訂正:A_idがかぶった場合、最も小さなB_idを選ぶ・・・が正しいです、すみません)

  • 元データ

SQL

1create table tbl_a(A_id int unique,name varchar(20),age int,s_id int); 2insert into tbl_a values 3(1,'Aさん',25,100), 4(2,'Bさん',22,100), 5(3,'Cさん',23,100), 6(4,'Dさん',22,100), 7(5,'Eさん',24,100), 8(6,'Fさん',24,200); 9 10create table tbl_b (B_id int unique,tanto varchar(20),A_id int); 11insert into tbl_b values 12(1,'aさん',1), 13(2,'bさん',2), 14(3,'cさん',3), 15(4,'dさん',4), 16(5,'eさん',5), 17(6,'fさん',1), 18(7,'gさん',2), 19(8,'hさん',3), 20(9,'iさん',4), 21(10,'jさん',5); 22
  • 検索

SQL

1select * from tbl_a as t1 2left join 3tbl_b as t2 on t1.A_id=t2.A_id 4and exists(select 1 from tbl_b as t3 where t2.A_id=t3.A_id and t2.B_id<t3.B_id) 5where t1.s_id=100

投稿2017/11/01 00:45

編集2017/11/01 01:20
yambejp

総合スコア114572

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

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

kurofukuro

2017/11/01 06:50

お返事遅くなり申し訳ございません。 ご丁寧にコードまでいただいてとても、見やすくとても参考になりました。 有難うございます。無事動かすことが出来ました。 ありがとうございます。
guest

0

ベストアンサー

結合すると多い件数の方で結果が返却されると考えてください。
Aテーブルに対して、複数人の担当者がいるので当然Aテーブルの件数より多い結果になります。

Aテーブルを軸にAテーブルの件数のみとしたい場合には、複数の担当者を1件にする必要があります。
そうすると担当者のうち誰を1件とするかの条件を決めなければなりません。

以下は、担当者のID(B_ID)が一番小さい人の場合です。

SQL

1SELECT A.A_id,A.名前,fil_B.B_id 2FROM A LEFT OUTER JOIN ( 3 select * from B as main_B 4 where B_ID = (select min(B_ID) from B where A_ID=main_B.A_ID) 5 ) as fil_B 6 on A.A_id = fil_B.A_id 7where A.s_id = 100 8;

別解

s_idがテーブルA全体に対して小さな分布であるなら、以下の方が高速かもしれません。

SQL

1SELECT A_id, 名前, (select min(B_id) from B where A_ID=A.A_ID) as B_id 2FROM A 3where s_id = 100 4;

投稿2017/11/01 00:29

編集2017/11/01 05:17
sazi

総合スコア25138

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

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

kurofukuro

2017/11/01 06:49

お返事遅くなり申し訳ございません。 ご丁寧にコードまでいただいてとても、見やすくとても参考になりました。 有難うございます。こちらのやり方で無事動きました!
guest

0

やりたいことがイメージできていれば、ツールを使用することでテンプレートが簡単に作れます。
SQL Joins Visualizer

投稿2017/10/31 22:28

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

kurofukuro

2017/10/31 22:36

こんなサイトがあるとは・・・ 知りましせんでした。ありがとうございます! キーワード検索だけでなく、こういったツール検索にも目を向けたいと思います。 今回のように、AとBテーブルを合わせた上でAテーブルにしかないs_idで条件分岐させたい場合はどのようにしたらよろしいでしょうか。ご教授頂ければ幸いです。
退会済みユーザー

退会済みユーザー

2017/10/31 23:33

うーん。試してみましたけど、意図したとおりの結果が出力されていますね^^; 実際にこのデータで再現していますか?
退会済みユーザー

退会済みユーザー

2017/10/31 23:49

SELECT A.A_id,A.名前,B.B_id → SELECT A.A_id,B.担当者,B.B_id かな?
kurofukuro

2017/11/01 00:03

ご回答度たびありがとうございます。 実際にカラム数が多いので、共通の部分以外は省略しておりますが、 なぜかA_idの1~5までが、現状このままだと重複して2回出てきてしまう感じです・・・
退会済みユーザー

退会済みユーザー

2017/11/01 00:20

質問内容で再現するか確認してもらえますか? 私の環境では再現しないです。
退会済みユーザー

退会済みユーザー

2017/11/01 00:43

おぉ^^;いつのまにかテーブルに修正が入っている。。。 再現しました。
退会済みユーザー

退会済みユーザー

2017/11/01 00:49

B 側の絞込が必要なので、条件を追記すると良いです。 B_id の小さいものを採用するのか、担当者の辞書順なのか? その辺の仕様が決まれば、解決するかと。
kurofukuro

2017/11/01 06:37

お返事遅くなり申しわけございません。 はい!無事解決いたしました。 何度もご連絡ありがとうございます。
guest

0

where句で対象となるのは5件ですが
結合条件(on句)で当てはまるものが複数あればその分は増えます。
でないと、どちらを結合すれば良いか分かりませんし
複数引っ掛かれば、複数を結合し、2行出るのは然るべきことです。

結果を見るとwhere句は問題なく、on句がおかしいのではないですか?
SELECT A.A_id,A.名前,B.B_id FROM A LEFT OUTER JOIN B on A.A_id = B.A_id where A.s_id = 100;
と載せていただいていますが
結果からみるとon A.A_id = B.B_idになっているように思えるのですが・・・

SELECT A.A_id,A.名前,B.B_idの部分をSELECT A.A_id,B.名前,B.B_idにしたら
fさんとかgさんとか出て来ませんか?

on句を見直してみていただければと思います。

投稿2017/10/31 23:38

編集2017/10/31 23:40
yuki-saito

総合スコア928

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

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

kurofukuro

2017/10/31 23:59

ご回答ありがとうございます。 おっしゃる通りです。サイトへの記入ミスでした。 Bテーブルのとこを書き換えて再度投稿させていただきました。
kurofukuro

2017/11/01 00:01

A_idの1~5までが、現状このままだと重複して2回でてきてしまいます・・・
yuki-saito

2017/11/01 00:05

はい、それは先程の回答の通りです。 実際にBテーブルのA_idに1は2つありますよね? なのでAテーブルの1~5に対して、Bテーブルの2つがそれぞれくっついて10個になります。 fさん~jさんをカットして良い理由は分かりませんが、 そういう条件を指定してあげないと求める5件にはならないです。
yuki-saito

2017/11/01 00:09 編集

単純な話ならorder byで好きな順に並べてlimit 5などを付ければよいですが、 単純な話でないなら、5件だけにしたい理由や条件をSQLとしてしっかり表現しましょう。
kurofukuro

2017/11/01 00:09

ありがとうございます。 一つ疑問がすっきりしました。 また、Aテーブルの A.s_id = 100の条件を満たしてからBと外部結合というのはどのように記載すればよろしいでしょうか。
kurofukuro

2017/11/01 00:11

度々回答ありがとうございます。 勉強不足で申し訳ございません。 前者ではなく、今回は後者なのでアドバイスをもう少しいただければ幸いです。
yuki-saito

2017/11/01 00:19 編集

どちらの順で実行しても結果は変わらないですよ。 ①where句でAテーブルが5件になって、Bテーブルと結合すると10件になる。 ②結合で10件になって、where句でそのまま。 (s_id=200のFさんのA_idはは6ですが、Bテーブルに6はないので結合した時点から10件で、where句したところで全員がs_id=100なので、10件のままになります。) 実行順番は基本的にオプティマイザーがよきに計らってくれる部分なので あまり強制指定はやめた方が良いです。 もちろんオプティマイザーも絶対ではないので時に強制も必要な場面もありますが それはまだまだ先の話ではないでしょうか。 (実行計画など、ここを語ると長くなりそうなのでやめておきます。) いずれにしてもkurofukuroさんがやりたいことを実現するための方法は where句を先に効かせることではなく、5件にするための条件をSQLとして書くことです。
kurofukuro

2017/11/01 00:28

ありがとうございます。 今回の件であれば、サブクエなどを使ってという認識でよろしいでしょうか。
yuki-saito

2017/11/01 01:01 編集

そこはどういう風にしたいのかを知っている方にしか分かりません^^; 現状だと先程書いた通りで、 「単純な話ならorder byで好きな順に並べてlimit 5などを付ければよいですが、 単純な話でないなら、5件だけにしたい理由や条件をSQLとしてしっかり表現しましょう。」 としか、こちらからは言えないので 必要ならどういう条件で10件を5件にしたいのかを追記していただければと思います。
kurofukuro

2017/11/01 06:38

上記の方の条件でうまくいきました。 何度もアドバイスいただきありがとうございました。
yuki-saito

2017/11/01 06:39

よかったです^^ お疲れ様でした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問