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

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

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

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

Q&A

解決済

4回答

338閲覧

HAVING以下が理解できません

Hekomi

総合スコア11

SQL

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

0グッド

0クリップ

投稿2018/04/21 07:47

『達人に学ぶ SQL徹底指南書』でSQLの勉強をし始めたばかりです。
P.134のSQL文でHAVING以下が理解できず躓いています。

テーブル名:SupParts
列はsup、partの2列で14行
sup | part
A ボルト
A ナット
A パイプ
B ボルト
B パイプ
C ボルト
C ナット
C パイプ
D ボルト
D パイプ
E ヒューズ
E ナット
E パイプ
F ヒューズ

CREATE TABLE SupParts
(sup CHAR(32) NOT NULL,
part CHAR(32) NOT NULL,
PRIMARY KEY(sup, part));

INSERT INTO SupParts VALUES('A', 'ボルト');
INSERT INTO SupParts VALUES('A', 'ナット');
INSERT INTO SupParts VALUES('A', 'パイプ');
INSERT INTO SupParts VALUES('B', 'ボルト');
INSERT INTO SupParts VALUES('B', 'パイプ');
INSERT INTO SupParts VALUES('C', 'ボルト');
INSERT INTO SupParts VALUES('C', 'ナット');
INSERT INTO SupParts VALUES('C', 'パイプ');
INSERT INTO SupParts VALUES('D', 'ボルト');
INSERT INTO SupParts VALUES('D', 'パイプ');
INSERT INTO SupParts VALUES('E', 'ヒューズ');
INSERT INTO SupParts VALUES('E', 'ナット');
INSERT INTO SupParts VALUES('E', 'パイプ');
INSERT INTO SupParts VALUES('F', 'ヒューズ');

★求めるものは、数も種類も全く同じ部品を取り扱う供給業者のペアです。

★解答
SELECT SP1.sup, SP2.sup
FROM SupParts SP1, SupParts SP2
WHERE SP1.sup < SP2.sup /* 業者の組み合わせを作る /
AND SP1.part = SP2.part /
条件1.同じ種類の部品を扱う /
GROUP BY SP1.sup, SP2.sup
HAVING COUNT(
) = (SELECT COUNT() / 条件2.同数の部品を扱う /
FROM SupParts SP3
WHERE SP3.sup = SP1.sup)
AND COUNT(
) = (SELECT COUNT(*)
FROM SupParts SP4
WHERE SP4.sup = SP2.sup);

★疑問点
HAVING句の前まで
SELECT SP1.sup, SP2.sup
FROM SupParts SP1, SupParts SP2
WHERE SP1.sup < SP2.sup /* 業者の組み合わせを作る /
AND SP1.part = SP2.part /
条件1.同じ種類の部品を扱う */
GROUP BY SP1.sup, SP2.sup

s1 s2
A B
A C
A D
A E
B C
B D
B E
C D
C E
D E
E F
の11列になることは理解できました。

また最初のSELECT句に count() を加えると
s1 s2 count(
)
A B 2
A C 3
A D 2
A E 2
B C 2
B D 2
B E 1
C D 2
C E 2
D E 1
E F 1
となるのですが、これは以降のHAVING句を理解する手立てになるのでしょうか?

大変恐縮ですが、ご教授いただけるとありがたいです!
宜しくお願いいたします!!

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

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

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

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

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

guest

回答4

0

ベストアンサー

全てのDBMSで動くわけではありませんが、MySQL5.6でのヒントになるクエリです。

SQL

1SELECT SP1.sup, SP2.sup, COUNT(*) AS COUNT, 2( 3 SELECT COUNT(*) 4 FROM SupParts SP3 5 WHERE SP3.sup = SP1.sup 6) AS COUNT_LEFT, 7( 8 SELECT COUNT(*) 9 FROM SupParts SP4 10 WHERE SP4.sup = SP2.sup 11) AS COUNT_RIGHT 12FROM SupParts SP1, SupParts SP2 13WHERE SP1.sup < SP2.sup 14AND SP1.part = SP2.part 15GROUP BY SP1.sup, SP2.sup

By.SQL Fiddle

投稿2018/04/21 09:30

hihijiji

総合スコア4150

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

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

Hekomi

2018/04/21 10:35

ありがとうございます! 感動しました! COUNT、COUNT_LEFT、COUNT_RIGHT がすべて等しい数値になるものを選ぶということですね! sup sup COUNT COUNT_LEFT COUNT_RIGHT A B 2 3 2 A C 3 3 3 A D 2 3 2 A E 2 3 3 B C 2 2 3 B D 2 2 2 B E 1 2 3 C D 2 3 2 C E 2 3 3 D E 1 2 3 E F 1 3 1 助かりました!  本当にありがとうございました!
defghi1977

2018/04/21 10:37

やっぱSQLは言葉で表現するもんじゃねーな…
guest

0

まず, HAVING句直前までのクエリを実行してみましょう

SQL

1SELECT SP1.sup, SP2.sup, SP1.part 2FROM SupParts SP1, SupParts SP2 3WHERE SP1.sup < SP2.sup /* 業者の組み合わせを作る */ 4AND SP1.part = SP2.part; /* 条件1.同じ種類の部品を扱う */

するとサプライヤAとサプライヤBに共通する部品のリストが抽出されます.

このクエリから部品を省略しGROUP BY句を適用し, サプライヤの組み合わせ毎の取扱い部品数を計算可能としたのが次のクエリです.

SQL

1SELECT SP1.sup, SP2.sup, COUNT(*) 2FROM SupParts SP1, SupParts SP2 3WHERE SP1.sup < SP2.sup /* 業者の組み合わせを作る */ 4AND SP1.part = SP2.part /* 条件1.同じ種類の部品を扱う */ 5GROUP BY SP1.sup, SP2.sup;

ここで更にHAVING句内のサブクエリで「サプライヤAの取り扱っている部品数=リストのcount()」かつ「サプライヤBの取り扱っている部品数=リストのcount()」なるサプライヤの組み合わせを抽出しています.

SQL

1SELECT SP1.sup, SP2.sup, COUNT(*) 2FROM SupParts SP1, SupParts SP2 3WHERE SP1.sup < SP2.sup /* 業者の組み合わせを作る */ 4AND SP1.part = SP2.part /* 条件1.同じ種類の部品を扱う */ 5GROUP BY SP1.sup, SP2.sup 6HAVING COUNT(*) = (SELECT COUNT(*) /* 条件2.同数の部品を扱う */ 7FROM SupParts SP3 8WHERE SP3.sup = SP1.sup) 9AND COUNT(*) = (SELECT COUNT(*) 10FROM SupParts SP4 11WHERE SP4.sup = SP2.sup);

すると結果は「サプライヤAの取り扱っている部品数=サプライヤBの取り扱っている部品数」となり, 目的の「数も種類も全く同じ部品を取り扱う供給業者のペア」が求められたことになります.

投稿2018/04/21 09:14

編集2018/04/21 09:59
defghi1977

総合スコア4756

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

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

Hekomi

2018/04/21 09:56

早々にご回答いただき、本当にありがとうございます!! GROUP BY句を適用するところまでは、理解できました! しかし、やはり最後のHAVINGの部分の理解に苦しんでおります(>_<) <引用> ここで更にHAVING句内のサブクエリで「サプライヤAの取り扱っている部品数=リストのcount(*)」かつ「サプライヤBの取り扱っている部品数=リストのcount(*)」なるサプライヤの組み合わせを抽出しています. リストのcount(*)というのは、GROUP BY句まででできた s1 s2 A B A C A D A E B C B D B E C D C E D E E F のカウントという解釈でよろしかったでしょうか? このcount(*)は具体的には、どういう数値になるのでしょうか? また サブクエリ (SELECT COUNT(*) FROM SupParts SP3 WHERE SP3.sup = SP1.sup) がなぜ「サプライヤAの取り扱っている部品数」になり (SELECT COUNT(*) FROM SupParts SP4 WHERE SP4.sup = SP2.sup); がなぜ「サプライヤBの取り扱っている部品数」になるのでしょうか? 初心者であり的外れな質問になってしまっているかとは存じますが ご教授いただけるとありがたいです。
defghi1977

2018/04/21 10:05

まあSQLの中でも自己結合は鬼門中の鬼門なので混乱するのも致し方無しとは思います. クエリにCOUNT(*)を追加して実行してみると判りやすくなりますよ. > また サブクエリ (SELECT COUNT(*) FROM SupParts SP3 WHERE SP3.sup = SP1.sup) がなぜ「サプライヤAの取り扱っている部品数」になり (SELECT COUNT(*) FROM SupParts SP4 WHERE SP4.sup = SP2.sup); がなぜ「サプライヤBの取り扱っている部品数」になるのでしょうか? 上で FROM SupParts SP1 とあるので, サブクエリ中の"SP1.sup"は固定値みたいなものです. なので, クエリ中のサプライヤとSupPartsテーブル内のサプライヤとを比較し, COUNT(*)で一致したレコード数を求めています. つまり, これはサプライヤが取り扱っている部品数になります.
Hekomi

2018/04/21 10:38

ご回答、ありがとうございます! 鬼門中の鬼門なのですね((+_+)) これからも、しばらく苦難の道が予想されます…。 またお助けいただければありがたいです!
defghi1977

2018/04/21 10:43

使いこなせるようになるとこれほど心強いものはないのですが, いかんせんさっきのあなたのようにSQLの意味について周りに解説するのが非常に辛いという諸刃の剣です. (理解には多分に数学的なセンスが必要となるので) とは言え, 難しいSQLを読めるようになると大抵のSQLはすらすらと読み解けるようになるのでトレーニングとしては良い題材かもしれません.
Hekomi

2018/04/21 10:48

早々にご回答いただき、本当に心強かったです! 数学的センスに関しては残念な身ですが 精進していきたいと思います! ありがとうございました!!
guest

0

答えになるかわからないですが、
havingは、whereとgroup byの後に実行されるので、count(*)はその件数になるかと思います。

投稿2018/04/21 08:41

py4s-tnk

総合スコア201

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

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

Hekomi

2018/04/21 10:39

初心者の拙い質問にご回答いただき ありがとうございます! どうにか、理解することができました!
guest

0

SQLを実行できる環境は用意されているでしょうか?

達人に学ぶ SQL徹底指南書

SQL入門用としては難し過ぎるかと。
SQL入門を何か月やってから中級編として使っては?

投稿2018/04/21 19:15

Orlofsky

総合スコア16415

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

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

Hekomi

2018/04/21 23:01

ご回答いただき、ありがとうございます! MySQL Workbenchを使って勉強をすすめております。 残念ながらご指摘通り、躓いてばかりです。 「スッキリわかるSQL入門 ドリル215問付き」も併用しながら 学習を進めております。 また躓き凹んでいた際には助けていただけると嬉しいです!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問