SQL-VSがどこにあるか


202

次の2つのテーブルがあります。

1. Lecturers (LectID, Fname, Lname, degree).
2. Lecturers_Specialization (LectID, Expertise).

最も専門性の高い講師を探したい。私がこれを試しても、うまくいきません:

SELECT
  L.LectID, 
  Fname, 
  Lname 
FROM Lecturers L, 
     Lecturers_Specialization S
WHERE L.LectID = S.LectID
AND COUNT(S.Expertise) >= ALL (SELECT
  COUNT(Expertise)
FROM Lecturers_Specialization
GROUP BY LectID);

しかし、これを試すとうまくいきます:

SELECT
  L.LectID,
  Fname,
  Lname 
FROM Lecturers L,
     Lecturers_Specialization S
WHERE L.LectID = S.LectID
GROUP BY L.LectID,
         Fname,
         Lname 
HAVING COUNT(S.Expertise) >= ALL (SELECT
  COUNT(Expertise)
FROM Lecturers_Specialization
GROUP BY LectID); 

理由は何ですか?ありがとう。


2
使用しているSQLのバージョン(MySQL、MS SQL、PostgreSQL、Oracleなど)を明確にできますか?また、「動作しない」と言った場合、結果が期待したものとは違うのですか、それともコンパイル/解析エラーがあるのですか?
jklemmack

2
MAXではなくALLを使用するのはなぜですか?何か利点はありますか?
スカン

回答:


351

WHERE句は、個々の行に条件を導入しますHAVING節は条件を導入します集計、すなわち、カウント、平均、最小、最大、合計などの単一の結果が複数の行から生成された選択の結果をます。クエリは、第2の種類の条件(つまり、集計の条件)を必要とするため、HAVING正しく機能します。

経験則として、 WHERE before GROUP BYHAVINGafterをGROUP BY。これはかなり原始的なルールですが、ケースの90%以上で役立ちます。

その間、ANSIバージョンの結合を使用してクエリを書き直すことができます。

SELECT  L.LectID, Fname, Lname
FROM Lecturers L
JOIN Lecturers_Specialization S ON L.LectID=S.LectID
GROUP BY L.LectID, Fname, Lname
HAVING COUNT(S.Expertise)>=ALL
(SELECT COUNT(Expertise) FROM Lecturers_Specialization GROUP BY LectID)

これはWHEREシータ結合条件として使用されていたものを排除します


39

HAVINGアグリゲートを操作します。COUNTは集約関数なので、WHERE句で使用することはできません。

これは、MSDNからの集計関数一部です。


30

まず、の実行順序、つまりFROM> WHERE> GROUP BY> HAVING> DISTINCT> SELECT> ORDER BYを知っておく必要があり ます。 以来、WHERE句が前に実行されます、GROUP BY節のレコードが適用することによってフィルタリングすることができないWHEREGROUP BYレコードを適用しました。

「HAVINGはWHERE句と同じですが、グループ化されたレコードに適用されます」。

最初にWHERE句が条件に基づいてレコードをフェッチし、次にGROUP BY句がそれに応じてレコードをグループ化し、次にHAVING句が所有条件に基づいてグループレコードをフェッチします。


この操作順序は常に使用されますか?クエリオプティマイザが順序を変更するとどうなりますか?
MSIS、

1
@MSISは、クエリオプティマイザーが順序を変更した場合でも、この順序が実行された場合と同じ結果になります。それは論理的な順序です。
スティーブン

18
  1. WHERE句はSELECT、INSERT、およびUPDATEステートメントで使用できますが、HAVINGはSELECTステートメントでのみ使用できます。

  2. WHEREは集計(GROUP BY)の前に行をフィルタリングしますが、HAVINGは集計の実行後にグループをフィルタリングします。

  3. 集計関数は、HAVING句に含まれるサブクエリ内にある場合を除いて、WHERE句では使用できませんが、集計関数はHAVING句で使用できます。

ソース


11

1つのクエリで両方の例を確認できませんでした。したがって、この例は役立つかもしれません。

  /**
INTERNATIONAL_ORDERS - table of orders by company by location by day
companyId, country, city, total, date
**/

SELECT country, city, sum(total) totalCityOrders 
FROM INTERNATIONAL_ORDERS with (nolock)
WHERE companyId = 884501253109
GROUP BY country, city
HAVING country = 'MX'
ORDER BY sum(total) DESC

これは、最初にcompanyIdでテーブルをフィルタリングし、次にそれを(国および都市で)グループ化し、さらにメキシコの都市の集計だけにフィルタリングします。集計ではcompanyIdは必要ありませんでしたが、GROUP BYを使用する前に、WHEREを使用して必要な行だけを除外することができました。


次のように変換できるので、良い例ではありません: `WHERE companyId = 884501253109 GROUP BY country、city HAVING country = 'MX'` to: `WHERE companyId = 884501253109、country = 'MX' GROUP BY
city`

[country]フィルタリングをWHEREに移動しただけの場合、[country]はGROUP BY集計に含まれていないため選択できないため、クエリはSELECT [country]からエラーになります。
Nhan

[国]をWHEREに移動すると、最適化のポイントが取られます。これは、後でGROUP BYに設定するデータセットが小さくなるためです。もちろん、これは可能な用途を説明するための単なる例です。HAVING sum(total)> 1000に変更できます。これは、WHEREおよびHAVINGを含めることで完全に有効なケースになります。
Nhan

9

where句は集約関数で使用できません。条件に基づいてレコードをフェッチする場合、レコードごとにテーブルレコードに移動し、指定した条件に基づいてレコードをフェッチするためです。したがって、そのときはwhere句を使用できません。句を使用すると、クエリの実行後に最終的に取得するresultSetで機能します。

クエリの例:

select empName, sum(Bonus) 
from employees 
order by empName 
having sum(Bonus) > 5000;

これにより、resultSetが一時メモリに格納され、having句がその作業を実行します。したがって、ここでは集約関数を簡単に使用できます。


2
GROUP BY句がないとHAVING句は使用できないと思います。HAVING句の位置-SELECT-> FROM-> WHERE-> GROUP BY-> HAVING-> ORDER BY
Morez

4

1. WHERE句ではなく、HAVING句を使用して集約関数を使用できます(例:min、max、avg)。

2. WHERE句はタプルごとにレコードタプルを削除しますHAVING句はグループのコレクションからグループ全体を削除します

ほとんどの場合、データのグループがある場合はHAVINGが使用され、行にデータがある場合はWHEREが使用されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.