はじめに
HAVING句を使って集合を切り分けることで、NULLを含まない集合の探し方を紹介します。
実行結果はこちらで確認できます。
例題
「はじめに」を読んだだけではどんな記事かいまいちピンとこないかなと思います。
タイトルにもありますが、COUNT(*)とCOUNT(列名)の違いとして
- パフォーマンス
- NULLのカウント
-
COUNT(*)
NULLをカウントする -
COUNT(列名)
NULLをカウントしない
-
両者の違いは、NULLしか含まないテーブルのSELECT文で顕著です。
Schema (MySQL v8.0)
CREATE TABLE members (
id INT NOT NULL PRIMARY KEY auto_increment,
name TEXT
);
INSERT INTO members VALUES (1, null), (2, null), (3, null);
Query
SELECT COUNT(*), COUNT(name) FROM members;
Results
COUNT(*) | COUNT(name) |
---|---|
3 | 0 |
この性質を利用すると、ある条件をクリアしたグループの抽出ができます。
この違い(性質)を次のようなケースの場合、利用できます。
お題
以下に、学校のクラスごとのメンバーのテーブルがあるとします。
このテーブルには、仮に、ある宿題の提出日があるとします。
宿題を提出したらsubmit_date
に提出日が入るとします。
この時、各グループの全てのメンバーが提出済みなグループだけを抽出したい時、クエリではどう表現しますか?
Schema (MySQL v8.0)
CREATE TABLE members (
id INT NOT NULL PRIMARY KEY auto_increment,
class TEXT,
submit_date DATETIME
);
INSERT INTO members VALUES
(1, 'A', '2021-12-18'),
(2, 'A', '2021-12-19'),
(3, 'B', null),
(4, 'B', '2021-12-20'),
(5, 'B', '2021-12-21'),
(6, 'C', null),
(7, 'D', '2021-12-22');
目視すると、グループAとグループDに所属の全メンバーが全員提出済みです。
このグループAとDの集合だけ抽出できる条件は、どんなものが考えられるでしょうか。
Query
ヒントというか、答えは
COUNT(*) と COUNT(submit_date) が一致するという性質です。
各グループの、COUNT(*) と COUNT(submit_date) をみてみると
- グループAの
- COUNT(*): 2
- COUNT(submit_date): 2
- グループBの
- COUNT(*): 3
- COUNT(submit_date): 2
- グループCの
- COUNT(*): 1
- COUNT(submit_date): 0
- グループDの
- COUNT(*): 1
- COUNT(submit_date): 1
という感じになります。
SELECT class
FROM members
GROUP BY class
HAVING COUNT(*) = COUNT(submit_date)
なので、このクエリだと、AとDがTRUEになることが分かりますよね。
Results
class |
---|
A |
D |
本日は以上です。
次は、この条件をCASE式を使って求めてみます。
参照
114 - 116p
アウトプット100本ノック実施中