HAVINGとWHEREの違いは何ですか?


261

私は間違った方法でグーグルをしているに違いない、または私には愚かな瞬間があります。

違いは何だHAVINGWHEREにおけるSQL SELECT文は?

編集:私はスティーブンの答えを正しい答えとしてマークしました。リンクに重要な情報が含まれているからです:

GROUP BY使用しない場合HAVINGWHERE句のように動作します

私が目にした状況WHEREはそうではなくGROUP BY、私の混乱が始まったところです。もちろん、これがわかるまでは、質問でそれを指定することはできません。


44
引用する行は、重要な部分ではありません。wcmが指摘したように、重要な点HAVINGは、それがポスト集約フィルターであるのに対してWHERE、プレ集約フィルターであるということです。
Nick Chammas 2012年

このリンクは、より良い、より下のすべてのコメントよりも、それを理解するために私を助けたいくつかのいずれかが、これで助けを得ることができると思ったcodeproject.com/Articles/25258/...
Lijin Durairaj

回答:



369

HAVING:集計が行われたの状態をチェックするため使用されます。
WHERE:集計が行われる前に条件をチェックするため使用されます。

このコード:

select City, CNT=Count(1)
From Address
Where State = 'MA'
Group By City

マサチューセッツ州のすべての都市と各都市の住所数の表を提供します。

このコード:

select City, CNT=Count(1)
From Address
Where State = 'MA'
Group By City
Having Count(1)>5

5つ以上の住所と各都市の住所数を含むMAの都市のテーブルを提供します。


7
これは受け入れられる答えになるはずです。「持つ」と「どこ」の違いは、これをすぐに明らかにします。
ポール・

27

私にとって最大の違いはHAVING、SQL言語から削除された場合、以前とほぼ同じように生活が続くことです。確かに、マイノリティクエリは派生テーブルやCTEなどを使用して書き換える必要がありますが、結果として、それらのクエリは間違いなく理解しやすく、維持しやすいでしょう。たぶん、ベンダーのオプティマイザコードは、これを説明するために書き直す必要があります。これも、業界内での改善の機会です。

ここで、少しのWHERE間、言語から削除することを検討してください。今回は、存在するクエリの大部分は、明白な代替構成なしで書き直す必要があります。コーダーは、前の句をシミュレートする句をDUAL使用して、(たとえばOracleで)正確に1行を含むことがわかっているテーブルへの内部結合などのクリエイティブを取得する必要があります。そのような構造は工夫されるでしょう。言語に欠けているものがあり、結果として状況が悪化することは明らかです。ONWHERE

TL; DR私たちはHAVING明日失う可能性があり、事態は悪化せず、おそらくより良いでしょうが、同じことは言えませんWHERE


ここでの回答から、多くの人々は、HAVING条項がGROUP BY条項なしで使用できることを理解していないようです。この場合、HAVING句はテーブル式全体に適用され、SELECT句に現れるのは定数のみです。通常、このHAVING句には集計が含まれます。

これは思ったより便利です。たとえば、次のクエリを検討して、name列がのすべての値に対して一意であるかどうかをテストしますT

SELECT 1 AS result
  FROM T
HAVING COUNT( DISTINCT name ) = COUNT( name );

可能な結果は2つだけです。HAVING句がtrueの場合、結果はvalueを含む単一行になります1。それ以外の場合、結果は空のセットになります。


それは「SELECT COUNT(DISTINCT name)= COUNT(name)FROM T」と同等ですか?
MSpreij

@MSpreijそれがうまくいくかどうかはわかりませんが、SQL Server 2005では機能しませんが、最初のバージョンでは機能します
Joe

22

WHEREキーワードを集計関数で使用できなかったため、SQLにHAVING句が追加されました。

詳細については、このw3schoolsリンクを確認してください。

構文:

SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value

次のようなクエリ:

SELECT column_name, COUNT( column_name ) AS column_name_tally
  FROM table_name
 WHERE column_name < 3
 GROUP 
    BY column_name
HAVING COUNT( column_name ) >= 3;

...次のように、派生テーブルを使用して(およびを省略してHAVING)書き換えることができます。

SELECT column_name, column_name_tally
  FROM (
        SELECT column_name, COUNT(column_name) AS column_name_tally
          FROM table_name
         WHERE column_name < 3
         GROUP 
            BY column_name
       ) pointless_range_variable_required_here
 WHERE column_name_tally >= 3;

3
あなたは要点を少し逃しました:HAVING派生テーブルが言語に追加されていなかったため、SQLになるまでリレーショナルに完成せず、必然的にHAVING冗長になったために追加されました。
onedaywhen

21

2つの違いは、GROUP BY句との関係にあります。

  • WHEREはGROUP BYの前にあります。SQLは、レコードをグループ化する前にWHERE句を評価します。

  • HAVINGはGROUP BYの後に来ます。SQLは、レコードをグループ化した後にHAVINGを評価します。

ステートメント図を選択

参考文献


GROUP BYとHAVINGはどちらもオプションであるため、図は両方のケースを示しています。矢印に従ってください。
Paul Sweatte 16

この質問に対する私の回答のクエリの例:SELECT 1 AS result FROM T HAVING...-あなたの図ではHAVING通過せずに到達することはできませんGROUP BYが、私の完全に有効で有用なクエリにはがありませんGROUP BY。マイナーポイント:SELECT句にリテラル値を含めるオプションはありません。
onedaywhen

@onedaywhen 暗黙のGROUP BYについて知っているので、なぜそれについて言及しなかったのですか?この振る舞いがあなたが期待しているものかどうか知っていますか?
Paul Sweatte

あなたは私を文脈から引用していると思います。質問は、MySQLの標準からの明らかな逸脱についてでした。私の回答の最後の段落を除くすべてが標準の動作を説明し、最後は「他の回答で言及されている暗黙のGROUP BY句」を暗示しています。あなたの図は(すべての)暗黙の振る舞いを説明することを目的としていると言っていますか?必要な動作を得るために必要なコードだけに固執するほうが便利ではないでしょうか?
onedaywhen

... 2番目のリンクであなたが何を示唆しているのかわかりません。望ましい結果は、図を修正して、前述の有効な(明示的な)パスを示すことです。考えてみてください。図はクエリ全体をカバーしていますが、質問はそのWHERE->HAVING部分にのみ関心があるので、細部に注意を払う価値があると思います。私の答えが間違っていると思われる場合は、編集するか、提案された修正をコメントに投稿してください。
onedaywhen

12

HAVINGなどの集計を使用している場合に使用されますGROUP BY

SELECT edc_country, COUNT(*)
FROM Ed_Centers
GROUP BY edc_country
HAVING COUNT(*) > 1
ORDER BY edc_country;

8

WHEREは、SQLによって返されるセットの制限として適用されます。SQLの組み込みセット操作とインデックスを使用するため、結果セットをフィルター処理する最速の方法です。可能な限り常にWHEREを使用してください。

一部の集約フィルターにはHAVINGが必要です。SQLが結果を取得、アセンブル、およびソートした後にクエリをフィルタリングします。したがって、それはWHEREよりもはるかに遅く、それを必要とする状況を除いて回避する必要があります。

SQL Serverでは、WHEREの方がはるかに高速な場合でも、HAVINGの使用を回避できます。しないでください。


SQL言語での派生テーブルのサポートは、「一部の集約フィルターにはHAVINGが必要である」というアサーションがfalseであることを意味します。
onedaywhen

1
それは良い点です。この回答を書いてから3年間で、以前はHAVINGを使用していたはずの派生テーブルの使用に確実に移行しました。HAVINGにまだ意味のあるユースケースがあるかどうか、私は考えていません。また、派生テーブルが普遍的にHAVINGよりも優れているかどうかもわかりません。
davidcl

7

WHERE句は集計関数で
は機能しません:このボーナスのように使用しないでください:テーブル名

SELECT name  
FROM bonus  
GROUP BY name  
WHERE sum(salary) > 200  

ここWHERE句を使用する代わりに、HAVINGを使用する必要があります。

GROUP BY句を使用しない場合、HAVING句はWHERE句として機能します

SELECT name  
FROM bonus  
GROUP BY name  
HAVING sum(salary) > 200  

4

違いの白黒WHEREHAVING節:

WHEREand HAVING句の主な違いは、WHERE行操作にHAVING使用され、列操作に使用されることです。

なぜHAVING条項が必要なのですか?

ご存知のように、集計関数は列に対してのみ実行できるため、WHERE句で集計関数を使用することはできません。したがって、HAVING句では集計関数を使用します。


2

GROUP BY使用しない場合、WHEREand HAVING句は基本的に同等です。

ただし、GROUP BYが使用される場合:

  • このWHERE句は、結果からレコードをフィルタリングするために使用されます。フィルタリングは、グループ化が行われる前に行われます。
  • このHAVING句は、グループから値をフィルタリングするために使用されます(つまり、グループへの集約が実行された後の条件をチェックするため)。

ここからのリソース


と場所は本質的に同等ではありません。実行中にエラーが発生します。HAVING句は集計関数にもGROUP BY句にも含まれていないため、HAVING句では無効です。
Nagendra Kumar

2

それを考える1つの方法は、having句がwhere句の追加のフィルターであるということです。

A 句は、結果からフィルタレコードを使用しています。フィルターは、グループ化が行われる前に行われます。HAVING句は、グループからフィルタ値に使用されています


1

集約クエリでは、(集約関数が使用される任意のクエリ)where句の述語は、集約された中間結果セットが生成される前に評価されます。

Have句の述語は、生成された後に集計結果セットに適用されます。これが、集計値の述語条件をWhere句ではなく、Having句に配置する必要がある理由であり、Wave句ではなくSelect句で定義されたエイリアスをWhere句では使用できない理由です。


1

私は問題を抱えていたとの間に別の違いが分かったWHEREとしますHAVING。インデックス付きの列に対しては同じように機能しません。

WHERE my_indexed_row = 123 行を表示し、他のインデックス付き行に対して自動的に「ORDER ASC」を実行します。

HAVING my_indexed_row = 123 最も古い「挿入された」行から最新の行まですべてを示し、順序付けはありません。


これが、使用していた特定のSQLサーバーの実装の偶然ではなく、2つの間の明確な違いであることをどのようにして知っていますか?
JdeBP

MariaDBでテストしました。8年前に使用していたSQLサーバーが異なる結果をもたらしたと思います。
Simmoniz

0

ここから。

SQL標準では、HAVINGはGROUP BY句の列または集計関数で使用される列のみを参照する必要があります

データベース行に適用されるWHERE句とは対照的


ソースによると、「SQL標準から構文が削除されたため、列位置の使用は推奨されていません。」悲しいことに、これは間違っています。標準から何も削除されないため、皮肉なことにHAVING、派生テーブルによって「非推奨」にされた後も数十年は残っています。
2016年

少し文句はあるが、引用は正しくない。例:検討SELECT 1 FROM T HAVING COUNT(*) >= 1;- GROUP BY句の列(なし)も集計関数の列も参照しない(クエリが列をまったく参照しない)。
2016年

0

プロジェクトに取り組んでいる間、これも私の質問でした。上記のように、HAVINGはすでに見つかったクエリ結果の条件をチェックします。ただし、WHEREはクエリの実行中に条件をチェックするためのものです。

これを説明する例を挙げましょう。次のようなデータベーステーブルがあるとします。

usertable {int userid、date datefield、int dailyincome}

次の行がテーブルにあると仮定します。

1、2011-05-20、100

1、2011-05-21、50

1、2011-05-30、10

2、2011-05-30、10

2、2011-05-20、20

今、私たちは、取得したいuserid秒とsum(dailyincome)そのsum(dailyincome)>100

私たちが書いた場合:

SELECT userid、sum(dailyincome)FROM usertable WHERE sum(dailyincome)> 100 GROUP BY userid

これはエラーになります。正しいクエリは次のとおりです。

SELECT userid、sum(dailyincome)FROM usertable GROUP BY userid HAVING sum(dailyincome)> 100


0

HAVING句は、クエリクリックの結果セットに集約関数の結果をフィルタリングするために使用することができ、一方、句は、ベーステーブル内の値を比較するために使用されるWHERE ここに


0

GROUP BYを使用しない場合、WHERE句とHAVING句は基本的に同等です。

ただし、GROUP BYを使用する場合:

  • WHERE句は、結果からレコードをフィルタリングするために使用されます。フィルタリングは、グループ化が行われる前に行われます。
  • HAVING句は、グループから値をフィルタリングするために使用されます(つまり、グループへの集約が実行された後に条件をチェックするため)。

-1

HAVINGを使用して、集約関数の結果に基づいてクエリを制約します。EG select * blahblahblahグループのSOMETHINGがcount(SOMETHING)> 0であるグループ


-1

「どこに」の件名が行であるのに対し、「持つ」の件名はグループであるかもしれません。私は正しいですか?


3
回答を投稿する前に確認する必要があります。これは他人を誤解させる可能性があります。
pippin1289 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.