SQL WHERE, HAVINGについて

このQ&Aのポイント
  • SQLのWHERE句とHAVING句について説明します。
  • WHERE句はGROUP BY句よりも前に評価されるため、グループ化された結果を利用できません。
  • HAVING句はGROUP BY句によってグループ化されたデータに対し、絞り込みの条件を指定することができます。
回答を見る
  • ベストアンサー

SQL WHERE, HAVING について

こんにちは。さっそくですが、 白男川 恵さん著作による 「Oracle Master Bronze 演習問題 SQL基礎I」 の問95について質問させていただきます。 問題文 CAT_ID列の値が20であるPRICE列の最大値を求めたい。 実行すべきSQL文として正しいものを選びなさい。 とあり、正解は (B) SELECT cat_id, MAX(price) FROM itemlist HAVING cat_id = 20 GROUP BY cat_id (C) SELECT cat_id, MAX(price) FROM itemlist WHERE cat_id = 20 GROUP BY cat_id なのですが、 WHERE句の使用法としては 大体の場合 WHERE (ターゲット) = (値) となると思うのですが、ターゲットのところが グループ関数でないのでこの場合は正解としてもよい、 ということでしょうか? 以下のサイトを別のタブで見ていただきたいのですが、 http://www.atmarkit.co.jp/fdb/rensai/tsql05/tsql05_1.html 「WHERE句とGROUP BY句を併用した場合、 WHERE → GROUP BYの順でクエリが評価されるため、 グループ化された結果をWHERE句の段階で利用できないのです。」 「HAVING句とGROUP BY句を利用した場合、 GROUP BY → HAVINGの順でクエリが評価され、 グループ化された結果に対し条件を指定することが可能です。」 http://www.atmarkit.co.jp/fdb/rensai/tsql05/tsql05_2.html 「HAVING句はGROUP BY句によってグループ化が行われたデータに対し、 絞り込みの条件を指定できます。 このため、絞り込み条件に集計関数を含めることが可能です。」 この設問の場合には WHERE→GROUP BYの順でも GROUP BY→HAVING の場合でもWHERE のターゲットがグループ関数で得られた値 で条件指定するわけではないので文法的にも正しく おなじ結果が得られる こういう解釈でよろしいのでしょうか? ご存知の方、教えていただけないでしょうか? よろしくお願いします。

noname#173931
noname#173931
  • Oracle
  • 回答数1
  • ありがとう数1

質問者が選んだベストアンサー

  • ベストアンサー
  • jjon-com
  • ベストアンサー率61% (1599/2592)
回答No.1

where句は group by句の前段階で行単位に対して実行されるフィルタ処理で, having句は group by句の後段階でグループ化単位に対して実行されるフィルタ処理。 -------- (C) SELECT cat_id, MAX(price) FROM itemlist WHERE cat_id = 20 GROUP BY cat_id は,次のような流れになります。 ↓ □where …cat_id = 20 の行だけを次段階へ送る ↓ □group by …cat_idでグループ化 (今回は,全行がcat_id=20なので1グループになります) ↓ □having …(無し) ↓ □select …グループ単位でmax(price)を表示 -------- > (B) SELECT cat_id, MAX(price) FROM itemlist > HAVING cat_id = 20 GROUP BY cat_id は間違いです。group by句とhaving句は次の順に指定しなければなりません。 SELECT cat_id, MAX(price) FROM itemlist GROUP BY cat_id HAVING cat_id = 20 上記の修正後は,次のような流れになります。 ↓ □where …(無し) ↓ □group by …cat_idでグループ化(複数グループになります) ↓ □having …cat_id=20のグループだけを次段階へ送る ↓ □select …グループ単位でmax(price)を表示 -------- > WHERE のターゲットがグループ関数で得られた値 > で条件指定するわけではないので文法的にも正しく > おなじ結果が得られる > こういう解釈でよろしいのでしょうか? はい,その解釈でよいでしょう。

noname#173931
質問者

お礼

お礼が遅れてしまい申しわけありません いつも解説していただきありがとうございます。 GROUP BY、HAVING の利用の仕方を教えていただき 参考にさせていただきます。 文法的な解釈のしかたについての あやふやな部分も確認していただき 理解を深めることができました。 貴重な時間をさいての回答、ありがとうございました。

関連するQ&A

  • なぜ、WHERE句とHAVING句があるのか?

    なぜ、WHERE句とHAVING句があるのか? SQLを学んでいる時に、疑問に思ったことがあります。 それは、「なぜ、WHERE句とHAVING句があるのか?」ということです。 この2つは、 ・WHERE句 → 表から取り出す行の条件を指定 ・GROUP BY句 → グループ化した結果から取り出す行の条件を指定 という違いがあることは分かっています。 ですが、おなじ「行のかたまりに対する抽出条件」を指定しているのに、 なぜ、わざわざ2つに分ける必要があったのでしょうか? 分けないと不都合が生じるのでしょうか。 もし、明瞭簡潔に説明できる方がいらっしゃいましたら、教えていただけないでしょうか。

  • なぜ、WHERE句とHAVING句があるのか?(質問文修正版)

    なぜ、WHERE句とHAVING句があるのか?(質問文修正版) SQLを学んでいる時に、疑問に思ったことがあります。 それは、「なぜ、WHERE句とHAVING句があるのか?」ということです。 この2つは、 ・WHERE句 → 表から取り出す行の条件を指定 ・HAVING句 → グループ化した結果から取り出す行の条件を指定 という違いがあることは分かっています。 ですが、おなじ「行のかたまりに対する抽出条件」を指定しているのに、 なぜ、わざわざ2つに分ける必要があったのでしょうか? 分けないと不都合が生じるのでしょうか。 もし、明瞭簡潔に説明できる方がいらっしゃいましたら、教えていただけないでしょうか。 ※本質問は、質問内容に質問の主旨が変わってしまう大きな誤りがあったため、いったん締め切り後、再掲載させていただきました。

  • SQL HAVING句の使い方について

    以下のテーブルAとテーブルBを結合して結果テーブルを出力したいと考えています。 (テーブルA上のIDのカウントした数をテーブルBに結合して出力したい。) テーブルA ----------- CATE ID aaa 001 bbb 001 ccc 003 ddd 004 テーブルB ----------- ID NAME 001 101 002 102 003 103 004 104 結果テーブル ---------------------- ID NAME COUNT 001 101 2 002 102 0 003 103 1 004 104 1 そこで、 =================================== SELECT B.ID, B.NAME, COUNT(A.ID) FROM TABLE_A B, TABLE_B B GROUP BY B.ID, B.NAME, A.ID HAVING A.ID = B.ID =================================== とSQLを書いてみましたが、 002 102 0 のテーブルAにIDが存在していない列が結果として表示されませんでした。 WHERE句でいう「WHERE A.ID =* B.ID」のようなことを行いたいのですが、どのように行えばよいでしょうか? よろしくお願いいたします。

  • 2つのSQL文で結果に差違が発生する

    私の知識ではお手上げのため、ご教授願いたいのですが、 下記のようなテーブルが仮にあったとして、レコードがそれぞれいくつか入っています。 【itemsテーブル】   id・・・・・連番   cat_id・・・category.id   price ・・・価格   max_num ・・セット数   date・・・・発売日 【categioryテーブル】   id・・・・・連番   cat_name・・カテゴリ名 【orderテーブル】   id・・・・・連番   item_id ・・items.id   paid_price・支払価格 以下の2つのSQL文を実行させた場合、「total_price」の値に違いは発生しますか? 【SQL文 A】----------------------------- SELECT items.cat_id, `category`.`cat_name`, SUM(`items`.`price` * `items`.`max_num`) AS `total_price`, SUM(IF(`order`.`paid_price` > 0, `order`.`paid_price`, 0)) AS `total_paid`, SUM(IF(`order`.`paid_price` = 0 , `items`.`price`, 0)) AS `not_payment` FROM `items` INNER JOIN `category` ON (`items`.`cat_id` = `category`.`id`) INNER JOIN `order` ON (`items`.`id` = `order`.`item_id`) WHERE DATE_FORMAT(`items`.`date`, '%Y%m') = 201511 GROUP BY `items`.`cat_id` ORDER BY `items`.`cat_id` ASC ------------------------------------ 【SQL文 B】----------------------------- SELECT items.cat_id, `category`.`cat_name`, SUM(`items`.`price` * `items`.`max_num`) AS `total_price` FROM `items` INNER JOIN `category` ON (`items`.`cat_id` = `category`.`id`) WHERE AND DATE_FORMAT(`items`.`date`, '%Y%m') = 201511 GROUP BY `items`.`cat_id` ORDER BY `items`.`cat_id` ASC ------------------------------------ こちらで上記と同じようなSQL文を実行すると、Bで出てほしい値がAでは出てこないのです。 Aの場合は「WHERE DATE_FORMAT(`items`.`date`, '%Y%m') = 201511」が抽出条件として実行されていないような感じです。 すべてのレコードの「SUM(`items`.`price` * `items`.`max_num`) AS `total_price`」が計算されています。 Bだけで実行すればちゃんとほしい値が返ってきます。 何か間違っていますか?

    • ベストアンサー
    • MySQL
  • SQL 句の評価順

    SQL句の評価順について皆さんの意見をいただけないでしょうか? <ケース1:SELECTが最後> ・FROM ・WHERE ・GROUP ・HAVING ・ORDER ・SELECT <ケース2:SELECTがトップ> ・SELECT ・FROM ・WHERE ・GROUP ・HAVING ・ORDER <ケース3:ORDERの前にSELECT> ・FROM ・WHERE ・GROUP ・HAVING ・SELECT ・ORDER どのケースで評価されますでしょうか? ご教授お願いします。

  • WHERE句かHAVING句の書き方

    こんにちは id|時間 A|19:00 A|09:00 B|16:00 C|18:00 のようなデータがあって、現在時刻が20:00とします idでグループ化したデータの時間の最大値が、現在時刻の3時間前 (今回は17:00)よりも前または等しいIDだけ抽出するためには どういう条件式を書けば良いか、ヒントを頂けますでしょうか 今回の例でいうと、結果には B|16:00 のみ出てくるということです WHEREやHAVINGを使って試行錯誤してはみたのですが、どうしても 例でいうところの A|09:00とB|16:00 が出てきてしまう始末です (条件にあう方のデータをとってしまい、除外にならない) IF文をうまいこと混ぜればいけるんでしょうか… コードは頑張って自分で作るので、考え方のヒントやこういうのを 使ってみるといいよ、といったアドバイスを頂けると助かります うまく質問の意図が伝わっているか不安ですが、ヨロシクお願いします mysql クライアントのバージョンは5.0.45です

    • ベストアンサー
    • MySQL
  • GROUP BY 句を使う時のWHERE と HAVINGの使い方の違いがいまいちよく分かりません

    SQL文でグループ化して、かつ抽出条件を 指定する時、WHERE を使うか HAVING を 使うかの違いがよく分かりません・・・。 どなたか分かりやすく教えて頂けませんでしょうか?

  • HAVING句でのBETWEEN演算子

    HAVING句でのBETWEEN演算子の使い方について教えていただけますでしょうか。 MS SQL SERVER のフロントエンドとしてMS ACCESS でパススルークエリを作成中です。 以下のようなテーブルがSQL SERVERにあります。 ID    TIME AAA   2005/06/01 00:00:10 BBB   2006/02/01 00:00:10 CCC   2006/03/01 00:00:10 AAA   2006/02/01 00:00:10 BBB   2006/02/02 00:00:10 CCC   2006/03/02 00:00:10 MS ACCESS パススルークエリで以下のようなSQL文を作成しました。 SQL文 SELECT ID, TIME FROM JOB WHERE TIME between '2006/01/01 00:00:00' and '2006/02/15 23:59:59' 結果 ID    TIME BBB   2006/02/01 00:00:10 AAA   2006/02/01 00:00:10 BBB   2006/02/02 00:00:10 抽出条件は TIME between '2006/01/01 00:00:00' and '2006/01/31 23:59:59' のままとし、IDをグルーピングしたいと思い以下のように書き換えましたが正しい記述では無いようでエラーとなってしまいます。 SELECT ID, TIME FROM JOB GROUP BY CODE HAVING TIME between '2006/01/01 00:00:00' and '2006/01/31 23:59:59' ORDER BY ID 欲しい結果 ID AAA BBB 正しい記述を教えていただけますでしょうか。 よろしくお願いいたします。

  • 1つのsql文でデータを取得したい

    phpとmysqlを連携させデータを取得しています。mysql5です。 現在は2つのテーブルからデータを取得するため以下のように2回のsql文を発行しています。 $sql = 'SELECT products_id, name, products_flag, comment1, IF("' . $products->beforedays . '" < DATE(create_date), "1", "0") as new, FROM products WHERE status = ? AND del_flg = ? ORDER BY create_date DESC'; // 1回目のsqlで取得したproducts_idを参照し下記のsqlを実行 $sql = 'SELECT MIN(price1) as min_price1, MAX(price1) as max_price1, MIN(price2) as min_price2, MAX(price2) as max_price2, IFNULL(price2, price1) as price0, stock FROM products_class_detail WHERE products_id = ?'; これを1回のsqlにまとめる場合どのような書き方になるでしょうか? 自分なりに下記のようにしてみたところ動作はするのですが複数のデータが条件に 当てはまるはずがminとmaxがあるためか条件に当てはまる最後のデータのみしか 取得されませんでした。 ※試しにmin,maxを外すと複数のデータを取得できました。 $sql = 'SELECT products.products_id, products.name, products.products_flag, products.comment1, IF("' . $products->beforedays . '" < DATE(products.create_date), "1", "0") as new, MIN(products_class_detail.price1) as min_price1, MAX(products_class_detail.price1) as max_price1, MIN(products_class_detail.price2) as min_price2, MAX(products_class_detail.price2) as max_price2, IFNULL(products_class_detail.price2, products_class_detail.price1) as price0, products_class_detail.stock FROM products, products_class_detail WHERE products_class_detail.products_id = products.products_id AND products.status2 = ? AND products.del_flg = ? ORDER BY' . $where_sql; 商品の情報を取得するsqlで最後のorder句は商品の並び順の変更でユーザーの指定した 順番(新着順や価格順等)で表示するためのものです。 2回のsqlの場合は問題なく動作していたのですがで新着順や価格順に並び替えを行うため 1回のでsqlで行いたいと思っております。 新着順の場合は1回目のsqlに条件が入るので問題ないのですが価格順の場合は2回目の sqlに条件が入るので2回のsqlではうまく並び替えができませんでした。 ソースの短縮にもなり可能であれば1回のsqlで完結させたいのですがどうすればいいものか わからずつまづいております。 詳しい方がいらっしゃいましたら宜しくお願い致します。

  • VBA ACCESS SQL WHERE句の数値型の変数の記述の仕方

    いつもお世話になっております。 i = Me!ID ’数値型です sql = "DELETE FROM T_DELETE_ID WHERE DELETE_ID = ""i"";" CurrentDb.Execute (sql) としたところ、SQLのWHERE句の条件の指定の仕方が どうもうまくいきません。 sql = "DELETE FROM T_DELETE_ID WHERE DELETE_ID = 101;" CurrentDb.Execute (sql) のようにWHERE句の値を数字にしたら実行できます。 この場合はどのようにしたらよろしいでしょうか わかる方いらっしゃいましたら、。ご教示の程よろしくお願いいたします。