SQL - memiliki VS di mana

202

Saya memiliki dua tabel berikut:

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

Saya ingin mencari dosen dengan Spesialisasi paling banyak. Ketika saya mencoba ini, itu tidak berfungsi:

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);

Tetapi ketika saya mencoba ini, ia bekerja:

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); 

Apa alasannya? Terima kasih.

Adam Sh
sumber
2
Bisakah Anda mengklarifikasi versi SQL yang Anda gunakan (MySQL, MS SQL, PostgreSQL, Oracle, dll.). Juga, ketika Anda mengatakan "tidak berfungsi", apakah maksud Anda hasilnya tidak seperti yang Anda harapkan, atau bahwa ada kesalahan kompilasi / parse?
jklemmack
2
Mengapa Anda menggunakan ALL alih-alih MAX ?. Apakah ada manfaatnya?
skan

Jawaban:

352

WHEREklausa memperkenalkan suatu kondisi pada baris individual ; HAVINGklausa memperkenalkan kondisi pada agregasi , yaitu hasil seleksi di mana hasil tunggal, seperti jumlah, rata-rata, min, maks, atau jumlah, telah dihasilkan dari beberapa baris. Kueri Anda meminta jenis kondisi kedua (yaitu kondisi pada agregasi) karenanya HAVINGberfungsi dengan benar.

Sebagai aturan praktis, gunakan WHEREsebelum GROUP BYdan HAVINGsesudah GROUP BY. Ini adalah aturan yang agak primitif, tetapi berguna dalam lebih dari 90% kasus.

Saat melakukannya, Anda mungkin ingin menulis ulang kueri menggunakan versi ANSI dari gabungan:

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)

Ini akan menghilangkan WHEREyang digunakan sebagai syarat bergabung theta .

dasblinkenlight
sumber
40

HAVINGberoperasi pada agregat. Karena COUNTfungsi agregat, Anda tidak bisa menggunakannya dalam WHEREklausa.

Berikut ini beberapa bacaan dari MSDN tentang fungsi agregat.

Daniel Mann
sumber
30

Pertama-tama kita harus mengetahui urutan pelaksanaan Klausul yaitu DARI> DIMANA> KELOMPOK OLEH> HAVING> DISTINCT> SELECT> ORDER BY. Karena Klausa WHERE dieksekusi sebelum GROUP BY Clause, rekaman tidak dapat difilter dengan menerapkan WHERE ke GROUP BY rekaman terapan.

"MEMILIKI sama dengan klausa WHERE tetapi diterapkan pada catatan yang dikelompokkan".

pertama klausa WHERE mengambil catatan berdasarkan kondisi kemudian klausa GROUP BY mengelompokkannya sesuai dan kemudian klausa HAVING mengambil catatan grup berdasarkan kondisi yang ada.

Pardhu
sumber
Apakah urutan operasi ini selalu digunakan? Bagaimana jika pengoptimal permintaan mengubah urutan?
MSIS
1
@MSIS bahkan jika pengoptimal kueri mengubah urutan, hasilnya harus sama seperti jika urutan ini diikuti. Ini urutan yang logis.
Stephen
18
  1. Klausa WHERE dapat digunakan dengan pernyataan SELECT, INSERT, dan UPDATE, sedangkan HAVING hanya dapat digunakan dengan pernyataan SELECT.

  2. WHERE menyaring baris sebelum agregasi (KELOMPOK OLEH), sedangkan HAVING grup filter setelah agregasi dilakukan.

  3. Fungsi agregat tidak dapat digunakan dalam klausa WHERE kecuali dalam subquery yang terkandung dalam klausa HAVING, sedangkan fungsi agregat dapat digunakan dalam klausa HAVING.

Sumber

Venkata Krishna Reddy
sumber
11

Tidak melihat contoh keduanya dalam satu kueri. Jadi contoh ini mungkin bisa membantu.

  /**
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

Ini memfilter tabel pertama oleh companyId, lalu mengelompokkannya (berdasarkan negara dan kota) dan juga memfilternya ke agregat kota di Meksiko. CompanyId tidak diperlukan dalam agregasi tetapi kami dapat menggunakan WHERE untuk memfilter hanya baris yang kami inginkan sebelum menggunakan GROUP BY.

Nhan
sumber
itu bukan contoh yang baik karena Anda dapat mengonversi: `WHERE companyId = 884501253109 KELOMPOK OLEH negara, kota HAVING negara = 'MX'` ke: `WHERE companyId = 884501253109, negara = 'MX' GROUP BY
city`
Jika hanya memindahkan filter [negara] ke WHERE telah Anda sarankan, kueri akan salah dari SELECT [negara], karena [negara] tidak lagi termasuk dalam agregasi GROUP BY, sehingga tidak dapat dipilih.
Nhan
Poin Anda tentang pengoptimalan diambil saat memindahkan [negara] ke WHERE karena itu akan menjadi kumpulan data yang lebih kecil untuk GROUP BY nanti. Tentu saja ini hanya contoh untuk menggambarkan kemungkinan penggunaan. Kita dapat mengubah ke jumlah HAVING (total)> 1000 dan itu akan menjadi kasus yang benar-benar valid untuk menyertakan WHERE dan HAVING.
Nhan
9

Anda tidak dapat menggunakan mana klausa dengan fungsi agregat karena di mana mengambil catatan berdasarkan kondisi, itu masuk ke tabel catatan dengan catatan dan kemudian mengambil catatan berdasarkan kondisi yang kami berikan. Sehingga saat itu kita tidak bisa kemana klausa. Meskipun klausa berfungsi pada resultSet yang akhirnya kami dapatkan setelah menjalankan kueri.

Contoh permintaan:

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

Ini akan menyimpan resultSet dalam memori sementara, kemudian memiliki klausa akan melakukan tugasnya. Jadi kita dapat dengan mudah menggunakan fungsi agregat di sini.

Akash5288
sumber
2
Saya pikir kita tidak bisa menggunakan klausa HAVING tanpa klausa GROUP BY. Posisi HAVING Clause - SELECT -> FROM -> WHERE -> GROUP BY -> HAVING -> ORDER BY
Morez
4

1. Kita dapat menggunakan fungsi agregat dengan klausa HAVING bukan dengan klausa WHERE mis. Min, max, avg.

2. WHERE clause menghilangkan record tuple dengan tuple HAVING klausa menghilangkan seluruh grup dari kumpulan grup

Sebagian besar HAVING digunakan ketika Anda memiliki grup data dan DI MANA digunakan ketika Anda memiliki data dalam baris.

Mihir Trivedi
sumber