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

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

ただいまの
回答率

91.03%

  • PHP

    17729questions

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

  • MySQL

    5087questions

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

  • JOIN

    17questions

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

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

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 235

kurofukuro

score 13

前提・実現したいこと

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
1 aさん 1
2 bさん 2
3 cさん 3
4 dさん 4
5 eさん 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
1 aさん 1
2 bさん 2
3 cさん 3
4 dさん 4
5 eさん 5
6 fさん 1
7 gさん 2
8 hさん 3
9 iさん 4
10 jさん 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
1 Aさん 1
2 Bさん 2
3 Cさん 3
4 Dさん 4
5 Eさん 5
1 Aさん 1
2 Bさん 2
3 Cさん 3
4 Dさん 4
5 Eさん 5

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

補足情報(言語/FW/ツール等のバージョンなど)

より詳細な情報
環境は、
php 5.6
mysql 5.6
になります。
どうぞよろしくお願いいたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+4

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

  • 元データ
create table tbl_a(A_id int unique,name varchar(20),age int,s_id int);
insert into tbl_a values
(1,'Aさん',25,100),
(2,'Bさん',22,100),
(3,'Cさん',23,100),
(4,'Dさん',22,100),
(5,'Eさん',24,100),
(6,'Fさん',24,200);

create table tbl_b (B_id int unique,tanto varchar(20),A_id int);
insert into tbl_b values
(1,'aさん',1),
(2,'bさん',2),
(3,'cさん',3),
(4,'dさん',4),
(5,'eさん',5),
(6,'fさん',1),
(7,'gさん',2),
(8,'hさん',3),
(9,'iさん',4),
(10,'jさん',5);
  • 検索
select * from tbl_a as t1
left join 
tbl_b as t2  on t1.A_id=t2.A_id
and exists(select 1 from tbl_b as t3 where t2.A_id=t3.A_id and t2.B_id<t3.B_id)
where t1.s_id=100

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/01 15:50

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

    キャンセル

checkベストアンサー

+2

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

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

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

SELECT A.A_id,A.名前,fil_B.B_id 
FROM A LEFT OUTER JOIN (
  select * from B as main_B
  where B_ID = (select min(B_ID) from B where A_ID=main_B.A_ID)
 ) as fil_B
 on A.A_id = fil_B.A_id 
where A.s_id = 100
;

別解

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/01 15:49

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

    キャンセル

+2

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/01 07:36

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

    キャンセル

  • 2017/11/01 08:33

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

    キャンセル

  • 2017/11/01 08:49

    SELECT A.A_id,A.名前,B.B_id

    SELECT A.A_id,B.担当者,B.B_id
    かな?

    キャンセル

  • 2017/11/01 09:03

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

    キャンセル

  • 2017/11/01 09:20

    質問内容で再現するか確認してもらえますか?
    私の環境では再現しないです。

    キャンセル

  • 2017/11/01 09:43

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

    キャンセル

  • 2017/11/01 09:49

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

    キャンセル

  • 2017/11/01 15:37

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

    キャンセル

+1

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/11/01 08:59

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

    キャンセル

  • 2017/11/01 09:01

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

    キャンセル

  • 2017/11/01 09:05

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

    キャンセル

  • 2017/11/01 09:09 編集

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

    キャンセル

  • 2017/11/01 09:09

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

    キャンセル

  • 2017/11/01 09:11

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

    キャンセル

  • 2017/11/01 09: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として書くことです。

    キャンセル

  • 2017/11/01 09:28

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

    キャンセル

  • 2017/11/01 10:01 編集

    そこはどういう風にしたいのかを知っている方にしか分かりません^^;

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

    キャンセル

  • 2017/11/01 15:38

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

    キャンセル

  • 2017/11/01 15:39

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

    キャンセル

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

  • ただいまの回答率 91.03%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • PHP

    17729questions

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

  • MySQL

    5087questions

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

  • JOIN

    17questions

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