MySQLでHAVING
ではなくWHERE
の後に自分で作成した列(例えばselect 1 as "number"
)を配置する必要があるのはなぜですか?
WHERE 1
(カラム名の代わりに定義全体を書く)の代わりに何か欠点がありますか?
MySQLでWHEREではなくHAVINGの後に自分で作成した列(たとえば「select 1 as number」)を配置する必要があるのはなぜですか?
WHERE
はGROUP BY
の前に適用され、HAVING
は後に適用されます(そして集約をフィルタリングすることができます)。
一般に、これらの句のどちらでもエイリアスを参照することはできませんが、MySQL
では、GROUP BY
、ORDER BY
、およびSELECT
でHAVING
レベルのエイリアスを参照できます。
そして "WHERE 1"(カラム名の代わりに定義全体を書く)をする代わりに何か欠点がありますか?
計算式に集約が含まれていない場合は、それをWHERE
句に含める方がおそらくより効率的です。
すべての回答が重要なポイントに達しませんでした。
テーブルがあるとします。
CREATE TABLE `table` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`value` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `value` (`value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
そして、1から10までのidとvalueの両方を持つ10行を持っています:
INSERT INTO `table`(`id`, `value`) VALUES (1, 1),(2, 2),(3, 3),(4, 4),(5, 5),(6, 6),(7, 7),(8, 8),(9, 9),(10, 10);
次の2つのクエリを試してください。
SELECT `value` v FROM `table` WHERE `value`>5; -- Get 5 rows
SELECT `value` v FROM `table` HAVING `value`>5; -- Get 5 rows
まったく同じ結果が得られますが、HAVING句はGROUP BY句なしでも機能します。
違いは次のとおりです。
SELECT `value` v FROM `table` WHERE `v`>5;
エラー#1054 - 'where節'の未知の列 'v'
SELECT `value` v FROM `table` HAVING `v`>5; -- Get 5 rows
WHERE句を使用すると、条件で任意のテーブル列を使用できますが、エイリアスや集計関数は使用できません。 HAVING句を使用すると、選択した(!)列、別名、または集計関数を条件で使用できます。
これは、WHERE句がselectの前にデータをフィルタリングするのに対し、HAVING句はselectの後に結果のデータをフィルタリングするためです。
そのため、テーブルに多数の行がある場合は、WHERE句に条件を入れるとより効率的になります。
主な違いを確認するには、EXPLAINを試してください。
EXPLAIN SELECT `value` v FROM `table` WHERE `value`>5;
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
| 1 | SIMPLE | table | range | value | value | 4 | NULL | 5 | Using where; Using index |
+----+-------------+-------+-------+---------------+-------+---------+------+------+--------------------------+
EXPLAIN SELECT `value` v FROM `table` having `value`>5;
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
| 1 | SIMPLE | table | index | NULL | value | 4 | NULL | 10 | Using index |
+----+-------------+-------+-------+---------------+-------+---------+------+------+-------------+
WHEREまたはHAVINGがインデックスを使用しているのがわかりますが、行が異なります。
主な違いは、WHERE
name__はグループ化された項目(SUM(number)
など)には使用できないのに対し、HAVING
name__は使用できることです。
その理由は、WHERE
name__が行われる前グループ化が行われ、HAVING
name__が行われる後グループ化が行われるためです。
HAVING
は、あなたのGROUP BY
内の集約をフィルタリングするために使用されます。
たとえば、重複する名前を確認するには
SELECT Name FROM Usernames
GROUP BY Name
HAVING COUNT(*) > 1
両方ともデータをフィルターにかけるための条件について言うのに使用されるので、これらの2は最初のものと同じように感じるでしょう。どの場合でも、「where」の代わりに「having」を使用できますが、「having」の代わりに「where」を使用できない場合があります。これは、選択クエリでは、「選択」の前に「選択」の前にデータがフィルタ処理され、「選択」の後に「フィルタ処理」のデータが「保持」されるためです。そのため、実際にはデータベースに存在しないエイリアス名を使用する場合、「どこで」それらを識別できませんが、「持っている」ことができます。
例:テーブルStudentにstudent_id、name、birthday、addressを含めるようにします。Assumebirthdayはdate型です。
SELECT * FROM Student WHERE YEAR(birthday)>1993; /*this will work as birthday is in database.if we use having in place of where too this will work*/
SELECT student_id,(YEAR(CurDate())-YEAR(birthday)) AS Age FROM Student HAVING Age>20;
/*this will not work if we use ‘where’ here, ‘where’ don’t know about age as age is defined in select part.*/
WHEREデータがグループ化される前にフィルタ処理し、データがグループ化された後にフィルタ処理します。これは重要な違いです。 WHERE句によって削除された行は、グループに含まれません。これにより、計算値が変更され、HAVING句での値の使用に基づいてフィルタリングされるグループが影響を受ける可能性があります。
抜粋からの引用:Forta、Ben "Samsは10分でSQLを教える(第4版)(Samsは自分を教える...)。"。
持っていることは集約でのみ使用されますが、どこで非集約文で使用されます。