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

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

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

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

Q&A

解決済

4回答

3898閲覧

HAVING句でのAVGの使い方

m.g2017

総合スコア19

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

0グッド

0クリップ

投稿2017/05/20 05:44

「達人に学ぶSQL徹底指南書」(著者:ミック、発行:翔泳社)の
第1部、1-10 帰ってきたHAVING句 「集合にきめ細やかな条件を設定する」の内容でつまずいています。

テーブル名:TestResults
列はstudent_id|class|sex|scoreの4列で15行
student_id|class|sex|score
001 A 男 100
002 A 女 100
003 A 女 49
004 A 男 30
005 B 女 100
006 B 男 92
007 B 男 80
008 B 男 80
009 B 女 10
010 C 男 92
011 C 男 80
012 C 女 21
013 D 女 100
014 D 女 0
015 D 女 0

SELECT class
FROM TestResults
GROUP BY class
HAVING AVG(CASE WHEN sex = '男'
THEN score
ELSE 0 END)
< AVG(CASE WHEN sex = '女'
THEN score
ELSE 0 END);

実行結果
class


A
D

上記のsqlのHAVING句の部分で、
例えばclassがAの行の処理でなぜ男子の平均が(100+30+0+0)/4=32.5ではなく(100+30)/2=65になるのか?
また、女子の平均が(100+49+0+0)/4=37.25ではなく
(100+49)/2=74.5になるのか?

「達人に学ぶSQL徹底指南書」を読んだことのある方がいたら
お手数ですが回答をお願いします。

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

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

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

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

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

guest

回答4

0

仰る通り
平均を出すためには、0の代わりにnullにする必要がありますよね。

SQL

1HAVING AVG(CASE WHEN sex = '男' THEN score ELSE null END) 2< AVG(CASE WHEN sex = '女' THEN score ELSE null END)

投稿2017/05/20 06:36

hihijiji

総合スコア4150

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

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

0

ベストアンサー

Postgresでもやってみました、AとDで良いと思います。

sql

1 2SELECT class, 3AVG(CASE WHEN sex='男' THEN score ELSE 0 END), 4AVG(CASE WHEN sex='女' THEN score ELSE 0 END) 5FROM TestResults 6GROUP BY class; 7 8 class | avg | avg 9-------+------------------------+--------------------- 10 D | 0.00000000000000000000 | 33.3333333333333333 11 B | 50.4000000000000000 | 22.0000000000000000 12 C | 57.3333333333333333 | 7.0000000000000000 13 A | 32.5000000000000000 | 37.2500000000000000 14(4 rows) 15 16但し、NULLを使えは答えは異なります。NULLはAVEの対象外 17SELECT class, 18AVG(CASE WHEN sex='男' THEN score ELSE NULL END), 19AVG(CASE WHEN sex='女' THEN score ELSE NULL END) 20FROM TestResults 21GROUP BY class; 22 23 class | avg | avg 24-------+---------------------+--------------------- 25 D | | 33.3333333333333333 26 B | 84.0000000000000000 | 55.0000000000000000 27 C | 86.0000000000000000 | 21.0000000000000000 28 A | 65.0000000000000000 | 74.5000000000000000 29

投稿2017/05/20 06:38

編集2017/05/20 06:43
A.Ichi

総合スコア4070

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

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

m.g2017

2017/05/21 09:19

わざわざ実行結果まで確認してくれてありがとうございます。 nullの場合AVGの対象に含まないという点には気を付けます。
guest

0

書籍の誤りです。書かれているSQLについてはあなたの理解で合っています。
しかし、男女別々に正しく平均を出すには、hihijijiさんが回答されているようにCASEで値を置き換える際に0ではなくNULLにする必要があります。COUNT以外の集約関数はNULLを対象から除外するためです。

投稿2017/05/20 06:27

編集2017/05/20 08:23
SVC34

総合スコア1149

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

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

0

「集合にきめ細やかな条件を設定する 男 女」で検索すると、Googleブックスで該当部分のサンプルが表示されてビックリしました。「翔泳社の許可を受けてページを表示しています. 」だそうです。

で、その部分ですが、本側の記述ミスじゃないでしょうか?
もし環境があるならAVG(CASE WHEN sex = '男' THEN score ELSE 0 END)これもselect文で抽出してみてはどうでしょうか?

paizaのMySQLで次のコードをrunしてみたところでは、結果は43.3333でした

sql

1create table Test(class1 integer, class2 integer, val integer); 2insert into Test(class1, class2, val) values(1, 1, 100); 3insert into Test(class1, class2, val) values(1, 1, 30); 4insert into Test(class1, class2, val) values(1, 2, 100); 5select class1,AVG(CASE WHEN class2 = 1 THEN val ELSE 0 END) 6from Test 7GROUP BY class1;

投稿2017/05/20 06:21

hirohiro

総合スコア2068

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

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

hirohiro

2017/05/20 06:29

といいますか、「男子の平均は」と書かれているだけで、「AVGの結果が」とは書かれていませんでしたので、記述ミスというわけでもないのかもしれませんね。混乱はしますけど
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問