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

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

ただいまの
回答率

88.80%

mysqlのサブクエリに関して|複数のテーブルを使用し条件に合うレコードを抽出したい

受付中

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 2,574

DaikiYamada

score 11

サブクエリを勉強してます。

■やりたいこと
売上の平均以上を達成した社員の名前を抽出したい

■分からないこと(迷っていること)
//売上平均の算出 
//"select avg(sale) from sales";
//売上の平均以上を達成したsalesテーブルのレコードを抽出 
//select * from sales where sale >  (select avg(sale) from sales);

上記まではできました。がsalesのmember_idをもとに売上平均以上の社員名をsql文で
どう書けば良いのかわかりません。
以下のようなsql文を考えましたが、そもそも書き方が間違ってますか?
select * from members where member_id = (select member_id from sales where sale >  select avg(sale) from sales);


■前提条件
member_id, sale, month
1 , 75 , 4
2 , 200 , 5
3 , 15 , 6
4 , 700 , 5
5 , 672 , 4
6 , 56 , 8
7 , 231 , 9
8 , 459 , 8
9 , 8 , 7
10 , 120 , 4
売上合計:2,536
売上平均:253.6

member_id, name
1 , Tanaka
2 , Sato
3 , Suzuki
4 , Tsuchiya
5 , Yamada
6 , Sasaki
7 , Harada
8 , Takahashi
9 , Nishida
10 , Nakada

member_id, age
1 , 24
2 , 25
3 , 47
4 , 55
5 , 39
6 , 26
7 , 43
8 , 33
9 , 24
10 , 20
 -->
<?php

require_once('functions.php');

$dbh = connectDb();

$sql = "select * from members where member_id = (select member_id from sales order by sale desc limit 1)";
$stmt = $dbh->prepare($sql);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
//var_dump($rows);

foreach ($rows as $row) {
  echo "1.最大の売上を出した社員の名前:".$row['name']."<br>";
}
//var_dump($row['name']);


// 2.売上の平均以上を達成した社員の名前の算出方法
// 


$sql = "select avg(sale) from sales";
$stmt = $dbh->prepare($sql);
$stmt->execute();
$avg = $stmt->fetchAll(PDO::FETCH_ASSOC);
var_dump($avg);


echo "2.売上の平均以上を達成した社員の名前:"."<br>";
echo "1.30代以下の社員が達成した売上の合計:"."<br>";



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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

0

http://www.atmarkit.co.jp/ait/articles/1208/06/news118.html
サブクエリで複数行を返すような時はINを使います。

ただ、MySQLではサブクエリ+INを使った場合にパフォーマンスが出ないケースがあるので
https://www.google.co.jp/search?q=MySQL+%E3%82%B5%E3%83%96%E3%82%AF%E3%82%A8%E3%83%AA+in&oq=MySQL+%E3%82%B5%E3%83%96%E3%82%AF%E3%82%A8%E3%83%AA+in&aqs=chrome..69i57j0l5.3874j0j4&sourceid=chrome&es_sm=93&ie=UTF-8#
無理にサブクエリで実行するよりは
結果をPHPで整形してから別のクエリにするか、JOINして取得するのが無難そうです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

以下で、いかがでしょうか?
SELECT DISTINCT m.member_id, m.name 
FROM sales AS s INNER JOIN members AS m ON s.member_id = m.member_id 
WHERE s.sale > (SELECT AVG(sale) FROM sales);

実行結果
mysql> SELECT DISTINCT m.member_id, m.name
    -> FROM sales AS s INNER JOIN members AS m ON s.member_id = m.member_id
    -> WHERE s.sale > (SELECT AVG(sale) FROM sales);
+-----------+-----------+
| member_id | name      |
+-----------+-----------+
|         4 | Tsuchiya  |
|         5 | Yamada    |
|         8 | Takahashi |
+-----------+-----------+
3 rows in set (0.00 sec)

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

0

select * from members where member_id = (select member_id from sales where sale >  select avg(sale) from sales); 
このままだと動作しないですが、この方向で書き直すと多分次のようになると思います。
SELECT *
FROM members m
WHERE EXISTS (
  SELECT *
  FROM sales s
  WHERE m.member_id = s.member_id
  AND sale > (
    SELECT avg(sale) 
    FROM sales
  )
); 
これでも動作するんじゃないかと思います。
しかしサブクエリをネストすると重いと聞きますので、アナライズは行った方が良いかも知れません。
※実質最下層のサブクエリは固定値の取得だけなので、existsが速いかjoinが速いかという話になりそうですが…。
私ならKiyoshiMotokiさんが書かれたコードのようにjoinを使うと思います。
コードの可読性もそちらのほうが良いですし、売り上げデータを付けたくなってもjoinのほうなら簡単に対応できます。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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

  • トップ
  • PHPに関する質問
  • mysqlのサブクエリに関して|複数のテーブルを使用し条件に合うレコードを抽出したい