Apa perbedaan antara MEMILIKI dan DI MANA?


261

Saya harus googling dengan cara yang salah atau saya mengalami momen bodoh dalam waktu.

Apa perbedaan antara HAVINGdan WHEREdalam suatu SQL SELECTpernyataan?

EDIT: Saya telah menandai jawaban Steven sebagai jawaban yang benar karena berisi sedikit informasi penting pada tautan:

Ketika GROUP BYtidak digunakan, HAVINGberperilaku seperti WHEREklausa

Situasi yang saya lihat di WHEREdalam tidak ada GROUP BYdan di situlah kebingungan saya mulai. Tentu saja, sampai Anda tahu ini, Anda tidak dapat menentukannya dalam pertanyaan.


44
Baris yang Anda kutip sama sekali bukan kunci utama. Bit kunci, seperti yang ditunjukkan oleh wcm , adalah itu HAVINGadalah filter pasca-agregasi, sedangkan filter WHEREpra-agregasi.
Nick Chammas

tautan ini membantu saya untuk memahaminya lebih baik daripada semua komentar di bawah ini, mengira seseorang dapat memperoleh bantuan dari codeproject.com/Articles/25258/…
Lijin Durairaj

Jawaban:


94

HAVING menentukan kondisi pencarian untuk grup atau fungsi agregat yang digunakan dalam pernyataan SELECT.

Sumber


369

HAVING: digunakan untuk memeriksa kondisi setelah agregasi berlangsung.
WHERE: digunakan untuk memeriksa kondisi sebelum agregasi berlangsung.

Kode ini:

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

Memberi Anda tabel semua kota di MA dan jumlah alamat di setiap kota.

Kode ini:

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

Memberi Anda daftar kota di MA dengan lebih dari 5 alamat dan jumlah alamat di setiap kota.


7
Ini harus menjadi jawaban yang diterima. Perbedaan antara "memiliki" dan "di mana" membuat ini segera menjadi jelas.
Paul

27

Perbedaan nomor satu bagi saya: jika HAVINGdihapus dari bahasa SQL maka kehidupan akan berjalan kurang lebih seperti sebelumnya. Tentu saja, permintaan minoritas perlu ditulis ulang menggunakan tabel turunan, CTE, dll, tetapi mereka bisa lebih mudah dipahami dan dipertahankan sebagai hasilnya. Mungkin kode pengoptimal vendor perlu ditulis ulang untuk menjelaskan hal ini, lagi-lagi kesempatan untuk perbaikan dalam industri.

Sekarang pertimbangkan sejenak untuk menghapus WHEREdari bahasa. Kali ini mayoritas pertanyaan yang ada perlu ditulis ulang tanpa konstruk alternatif yang jelas. Coders harus mendapatkan kreatif misalnya gabung dalam ke tabel yang diketahui mengandung tepat satu baris (misalnya DUALdalam Oracle) menggunakan ONklausa untuk mensimulasikan WHEREklausa sebelumnya . Konstruksi seperti itu akan dibuat; akan jelas ada sesuatu yang hilang dari bahasa dan situasinya akan menjadi lebih buruk.

TL; DR kita bisa kehilangan HAVINGbesok dan segalanya tidak akan lebih buruk, mungkin lebih baik, tetapi hal yang sama tidak dapat dikatakan WHERE.


Dari jawaban di sini, tampaknya banyak orang tidak menyadari bahwa HAVINGklausa dapat digunakan tanpa GROUP BYklausa. Dalam hal ini, HAVINGklausa diterapkan ke seluruh ekspresi tabel dan mengharuskan hanya konstanta yang muncul dalam SELECTklausa. Biasanya HAVINGklausa akan melibatkan agregat.

Ini lebih bermanfaat daripada kedengarannya. Misalnya, pertimbangkan permintaan ini untuk menguji apakah namekolom tersebut unik untuk semua nilai di T:

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

Hanya ada dua kemungkinan hasil: jika HAVINGklausa itu benar maka hasil dengan menjadi satu baris berisi nilai 1, jika tidak hasilnya akan menjadi set kosong.


Apakah itu setara dengan "SELECT COUNT (DISTINCT name) = COUNT (name) FROM T"?
MSpreij

@ MSpreij Dont tahu jika itu bekerja untuk Anda, tetapi tidak bekerja pada SQL server 2005 tetapi yang pertama tidak
Joe

22

Klausa HAVING ditambahkan ke SQL karena kata kunci WHERE tidak dapat digunakan dengan fungsi agregat.

Lihat tautan w3schools ini untuk informasi lebih lanjut

Sintaksis:

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

Kueri seperti ini:

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;

... dapat ditulis ulang menggunakan tabel turunan (dan menghilangkan HAVING) seperti ini:

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
Anda telah sedikit melewatkan intinya: HAVINGditambahkan karena tabel turunan belum ditambahkan ke bahasa dan sampai mereka SQL tidak lengkap secara relasional dan begitu mereka pasti HAVINGmenjadi berlebihan.
onedaywhen

21

Perbedaan antara keduanya adalah dalam hubungan dengan klausa GROUP BY:

  • WHERE datang sebelum GROUP BY; SQL mengevaluasi klausa WHERE sebelum mengelompokkan catatan.

  • HAVING muncul setelah GROUP BY; SQL mengevaluasi HAVING setelah mengelompokkan catatan.

pilih diagram pernyataan

Referensi


Karena GROUP BY dan HAVING sama-sama opsional, diagram menunjukkan kedua kasus, cukup ikuti panah.
Paul Sweatte

Contoh kueri dari jawaban saya untuk pertanyaan ini: SELECT 1 AS result FROM T HAVING...- dalam diagram Anda, saya tidak dapat melakukannya HAVINGtanpa melewati GROUP BYtapi kueri yang benar-benar valid dan berguna tidak GROUP BY. Poin minor: Anda tidak memiliki opsi untuk memasukkan nilai literal dalam SELECTklausa.
onedaywhen

@onedaywhen Karena Anda tahu tentang GROUP implisit OLEH, mengapa Anda tidak menyebutkannya? Apakah Anda tahu apakah perilaku ini sesuai dengan yang Anda harapkan atau tidak?
Paul Sweatte

Saya pikir Anda mengutip saya di luar konteks. Pertanyaannya adalah tentang penyimpangan nyata mySQL dari Standar, semua kecuali paragraf terakhir dari jawaban saya menggambarkan perilaku Standar, dan yang terakhir menyinggung "klausa GROUP BY implisit yang disebutkan dalam jawaban lain ." Apakah Anda mengatakan diagram Anda dimaksudkan untuk menggambarkan (semua) perilaku implisit? Bukankah lebih bermanfaat untuk tetap menggunakan kode yang Anda butuhkan untuk mendapatkan perilaku yang diinginkan?
onedaywhen

... Saya tidak tahu perilaku apa yang Anda singgung di tautan kedua. Hasil yang diinginkan adalah Anda memperbaiki diagram untuk menunjukkan jalur (eksplisit) yang valid yang saya sebutkan. Pikirkan tentang hal ini: diagram mencakup seluruh kueri namun pertanyaannya hanya tertarik pada WHERE->HAVINGbagian itu, jadi saya pikir layak untuk memperhatikan detail. Jika menurut Anda jawaban saya salah, edit atau kirim koreksi yang disarankan di komentar.
onedaywhen

12

HAVINGdigunakan ketika Anda menggunakan agregat seperti GROUP BY.

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

8

WHERE diterapkan sebagai batasan pada set yang dikembalikan oleh SQL; ia menggunakan set oeprations dan indeks bawaan SQL dan karena itu adalah cara tercepat untuk menyaring set hasil. Selalu gunakan WHERE jika memungkinkan.

HAVING diperlukan untuk beberapa filter agregat. Ini memfilter kueri SETELAH sql telah mengambil, mengumpulkan, dan mengurutkan hasilnya. Oleh karena itu, ini jauh lebih lambat daripada DIMANA dan harus dihindari kecuali dalam situasi yang mengharuskannya.

SQL Server akan membiarkan Anda menggunakan HAVING bahkan ketika DI MANA akan jauh lebih cepat. Jangan lakukan itu.


Dukungan untuk tabel turunan dalam bahasa SQL berarti pernyataan Anda "MEMILIKI diperlukan untuk beberapa filter agregat" salah.
onedaywhen

1
Itu poin yang bagus. Dalam tiga tahun sejak saya menulis jawaban ini saya pasti bermigrasi ke arah menggunakan tabel turunan di mana saya sebelumnya akan menggunakan HAVING. Saya belum memikirkan pertanyaan apakah MEMILIKI masih memiliki beberapa kasus penggunaan yang masuk akal. Saya juga tidak tahu apakah tabel turunan secara universal akan berkinerja lebih baik daripada MEMILIKI.
davidcl

7

Klausa WHERE tidak berfungsi untuk fungsi agregat
berarti: Anda tidak boleh menggunakan bonus seperti ini: nama tabel

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

DI SINI Alih-alih menggunakan klausa WHERE Anda harus menggunakan HAVING ..

tanpa menggunakan klausa GROUP BY, klausa HAVING hanya berfungsi sebagai klausa WHERE

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

4

Perbedaan b / b WHEREdan HAVINGklausa:

Perbedaan utama antara WHEREdan HAVINGklausa adalah, WHEREdigunakan untuk operasi baris dan HAVINGdigunakan untuk operasi kolom.

Mengapa kita perlu HAVINGklausa?

Seperti yang kita ketahui, fungsi agregat hanya dapat dilakukan pada kolom, jadi kami tidak dapat menggunakan fungsi agregat dalam WHEREklausa. Oleh karena itu, kami menggunakan fungsi agregat dalam HAVINGklausa.


2

Ketika GROUP BYtidak digunakan, WHEREdan HAVINGklausa pada dasarnya setara.

Namun, kapan GROUP BYdigunakan:

  • The WHEREklausul digunakan untuk catatan filter dari hasilnya. Penyaringan terjadi sebelum pengelompokan dibuat.
  • The HAVINGklausul digunakan untuk nilai-nilai filter dari kelompok (yaitu, untuk memeriksa kondisi setelah agregasi ke dalam kelompok telah dilakukan).

Sumber daya dari Sini


memiliki dan di mana pada dasarnya tidak setara. itu akan memberikan kesalahan saat eksekusi. tidak valid dalam klausa HAVING karena tidak terkandung dalam fungsi agregat atau klausa GROUP BY.
Nagendra Kumar

2

Salah satu cara untuk memikirkannya adalah bahwa klausa memiliki adalah filter tambahan ke klausa mana.

Sebuah MANA klausa digunakan filter catatan dari hasilnya. Filter terjadi sebelum pengelompokan dibuat. Sebuah HAVING klausa digunakan untuk nilai-nilai filter dari kelompok


1

Dalam kueri agregat, (Kueri apa pun tempat fungsi agregat digunakan) Predikat dalam klausa di mana dievaluasi sebelum himpunan hasil antara agregat dihasilkan,

Predikat dalam klausa Memiliki diterapkan ke hasil agregat yang ditetapkan SETELAH itu telah dihasilkan. Itu sebabnya kondisi predikat pada nilai agregat harus ditempatkan di klausa Having, bukan di klausa Where, dan mengapa Anda bisa menggunakan alias yang didefinisikan dalam klausa Select dalam Klausa Having, tetapi tidak dalam klausa Where.


1

Saya punya masalah dan menemukan perbedaan lain antara WHEREdan HAVING. Itu tidak bertindak dengan cara yang sama pada kolom yang diindeks.

WHERE my_indexed_row = 123 akan menampilkan baris dan secara otomatis melakukan "ORDER ASC" pada baris yang diindeks lainnya.

HAVING my_indexed_row = 123 menunjukkan segalanya dari baris "yang dimasukkan" yang paling lama ke baris yang terbaru, tanpa urutan.


Bagaimana Anda tahu bahwa ini adalah perbedaan yang didefinisikan antara twain, daripada kecelakaan implementasi server SQL tertentu yang Anda gunakan?
JdeBP

Saya baru saja mengujinya di MariaDB. Saya kira itu adalah SQL server yang saya gunakan 8 tahun lalu yang menghasilkan hasil yang berbeda.
Simmoniz

0

Dari sini .

standar SQL mensyaratkan bahwa HAVING harus mereferensikan hanya kolom dalam klausa GROUP BY atau kolom yang digunakan dalam fungsi agregat

yang bertentangan dengan klausa WHERE yang diterapkan pada baris basis data


Sumber mengatakan, "Penggunaan posisi kolom sudah usang karena sintaks telah dihapus dari standar SQL." Sayangnya, ini salah: tidak ada yang pernah dihapus dari Standar, yang ironisnya adalah mengapa kita masih memiliki HAVINGbeberapa dekade setelah itu 'ditinggalkan' oleh tabel turunan.
onedaywhen

Agak bertele-tele tetapi kutipan tidak benar, mis. Pertimbangkan SELECT 1 FROM T HAVING COUNT(*) >= 1;- tidak merujuk kolom dalam GROUP BYklausa (tidak ada) atau kolom dalam fungsi agregat (referensi permintaan tidak ada kolom sama sekali).
onedaywhen

0

Saat mengerjakan sebuah proyek, ini juga pertanyaan saya. Seperti yang dinyatakan di atas, HAVING memeriksa kondisi pada hasil permintaan yang sudah ditemukan. Tapi DI MANA adalah untuk memeriksa kondisi saat kueri berjalan.

Biarkan saya memberi contoh untuk menggambarkan hal ini. Misalkan Anda memiliki tabel database seperti ini.

usertable {int userid, date datefield, int dailyincome}

Misalkan, baris-baris berikut ada dalam tabel:

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

Sekarang, kami ingin mendapatkan useriddan sum(dailyincome)yangsum(dailyincome)>100

Jika kita menulis:

SELECT userid, jumlah (dailyincome) DARI dapat digunakan WHERE jumlah (dailyincome)> 100 GROUP BY userid

Ini akan menjadi kesalahan. Kueri yang benar adalah:

SELECT userid, jumlah (dailyincome) DARI KELOMPOK dapat digunakan OLEH userid HAVING jumlah (dailyincome)> 100


0

Klausa WHERE digunakan untuk membandingkan nilai dalam tabel dasar, sedangkan klausa HAVING dapat digunakan untuk memfilter hasil fungsi agregat dalam kumpulan hasil kueri Klik di sini !


0

Ketika GROUP BY tidak digunakan, klausa WHERE dan HAVING pada dasarnya setara.

Namun, ketika GROUP BY digunakan:

  • Klausa WHERE digunakan untuk memfilter rekaman dari suatu hasil. Penyaringan terjadi sebelum pengelompokan dibuat.
  • Klausa HAVING digunakan untuk memfilter nilai dari grup (yaitu, untuk memeriksa kondisi setelah agregasi ke dalam grup telah dilakukan).

-1

Saya menggunakan HAVING untuk membatasi kueri berdasarkan hasil fungsi agregat. EG pilih * dalam grup blahblahblah oleh SOMETHING yang memiliki hitungan (SOMETHING)> 0


-1

Mungkin saja subjek "di mana" adalah baris, sedangkan subjek "memiliki" adalah sebuah kelompok. Apakah saya benar?


3
Anda harus yakin sebelum mengirim jawaban. Ini bisa menyesatkan orang lain.
pippin1289
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.