Saya mencoba untuk belajar SQL dan mengalami kesulitan untuk memahami pernyataan EXISTS. Saya menemukan kutipan tentang "ada" dan tidak memahami sesuatu:
Dengan menggunakan operator existing, subkueri Anda bisa mengembalikan nol, satu, atau banyak baris, dan ketentuannya hanya memeriksa apakah subkueri mengembalikan baris apa pun. Jika Anda melihat klausa pilih dari subkueri, Anda akan melihat bahwa itu terdiri dari satu literal (1); karena kondisi dalam kueri penampung hanya perlu mengetahui berapa banyak baris yang dikembalikan, data aktual yang dikembalikan subkueri tidak relevan.
Yang tidak saya mengerti adalah bagaimana kueri luar mengetahui baris mana yang diperiksa subkueri? Sebagai contoh:
SELECT *
FROM suppliers
WHERE EXISTS (select *
from orders
where suppliers.supplier_id = orders.supplier_id);
Saya memahami bahwa jika id dari tabel pemasok dan pesanan cocok, subkueri akan mengembalikan nilai true dan semua kolom dari baris yang cocok di tabel pemasok akan dikeluarkan. Apa yang tidak saya dapatkan adalah bagaimana subquery mengkomunikasikan baris spesifik mana (katakanlah baris dengan supplier id 25) harus dicetak jika hanya benar atau salah yang dikembalikan.
Tampak bagi saya bahwa tidak ada hubungan antara kueri luar dan subkueri.
Menurut Anda, apa yang dilakukan klausa WHERE di dalam contoh EXISTS? Bagaimana Anda sampai pada kesimpulan itu jika referensi SUPPLIERS tidak ada dalam klausul FROM atau JOIN dalam klausul EXISTS?
EXISTS menilai TRUE / FALSE, dan keluar sebagai TRUE pada kecocokan pertama kriteria - inilah mengapa bisa lebih cepat dari
IN
. Ketahuilah juga bahwa klausa SELECT di EXISTS diabaikan - YAITU:SELECT s.* FROM SUPPLIERS s WHERE EXISTS (SELECT 1/0 FROM ORDERS o WHERE o.supplier_id = s.supplier_id)
... harus mencapai kesalahan divisi dengan nol, tetapi tidak akan. Klausa WHERE adalah bagian terpenting dari klausa EXISTS.
Ketahuilah juga bahwa JOIN bukanlah pengganti langsung untuk EXISTS, karena akan ada catatan induk duplikat jika ada lebih dari satu catatan anak yang terkait dengan induk.
sumber
EXISTS
Keluar, mengembalikan TRUE pada pertandingan pertama - karena pemasok ada setidaknya satu kali dalam tabel ORDERS. Jika Anda ingin melihat duplikasi data SUPPLIER karena memiliki lebih dari satu hubungan anak di ORDERS, Anda harus menggunakan GABUNG. Tetapi sebagian besar tidak menginginkan duplikasi itu, dan menjalankan GROUP BY / DISTINCT dapat menambah overhead ke kueri.EXISTS
lebih efisien daripadaSELECT DISTINCT ... FROM SUPPLIERS JOIN ORDERS ...
di SQL Server, belum pernah diuji di Oracle atau MySQL belakangan ini.Anda dapat menghasilkan hasil yang identik baik menggunakan
JOIN
,EXISTS
,IN
, atauINTERSECT
:SELECT s.supplier_id FROM suppliers s INNER JOIN (SELECT DISTINCT o.supplier_id FROM orders o) o ON o.supplier_id = s.supplier_id SELECT s.supplier_id FROM suppliers s WHERE EXISTS (SELECT * FROM orders o WHERE o.supplier_id = s.supplier_id) SELECT s.supplier_id FROM suppliers s WHERE s.supplier_id IN (SELECT o.supplier_id FROM orders o) SELECT s.supplier_id FROM suppliers s INTERSECT SELECT o.supplier_id FROM orders o
sumber
Jika Anda memiliki klausa where yang terlihat seperti ini:
WHERE id in (25,26,27) -- and so on
Anda dapat dengan mudah memahami mengapa beberapa baris dikembalikan dan beberapa tidak.
Ketika klausa where seperti ini:
WHERE EXISTS (select * from orders where suppliers.supplier_id = orders.supplier_id);
itu hanya berarti: mengembalikan baris yang memiliki catatan yang ada di tabel pesanan dengan id yang sama.
sumber
Model tabel database
Mari kita asumsikan kita memiliki dua tabel berikut dalam database kita, yang membentuk hubungan tabel satu-ke-banyak.
The
student
tabel orangtua, danstudent_grade
adalah tabel anak karena memiliki kolom student_id Key Foreign referensi id Primary Key kolom dalam tabel mahasiswa.The
student table
berisi dua catatan berikut:| id | first_name | last_name | admission_score | |----|------------|-----------|-----------------| | 1 | Alice | Smith | 8.95 | | 2 | Bob | Johnson | 8.75 |
Dan,
student_grade
tabel tersebut menyimpan nilai yang diterima siswa:| id | class_name | grade | student_id | |----|------------|-------|------------| | 1 | Math | 10 | 1 | | 2 | Math | 9.5 | 1 | | 3 | Math | 9.75 | 1 | | 4 | Science | 9.5 | 1 | | 5 | Science | 9 | 1 | | 6 | Science | 9.25 | 1 | | 7 | Math | 8.5 | 2 | | 8 | Math | 9.5 | 2 | | 9 | Math | 9 | 2 | | 10 | Science | 10 | 2 | | 11 | Science | 9.4 | 2 |
SQL SUDAH ADA
Katakanlah kita ingin mendapatkan semua siswa yang telah menerima nilai 10 di kelas Matematika.
Jika kita hanya tertarik pada pengenal siswa, maka kita dapat menjalankan kueri seperti ini:
SELECT student_grade.student_id FROM student_grade WHERE student_grade.grade = 10 AND student_grade.class_name = 'Math' ORDER BY student_grade.student_id
Namun, aplikasi tertarik untuk menampilkan nama lengkap a
student
, bukan hanya pengenalnya, jadi kami juga membutuhkan info daristudent
tabel.Untuk memfilter
student
record yang memiliki nilai 10 dalam Matematika, kita dapat menggunakan operator SQL EXISTS, seperti ini:SELECT id, first_name, last_name FROM student WHERE EXISTS ( SELECT 1 FROM student_grade WHERE student_grade.student_id = student.id AND student_grade.grade = 10 AND student_grade.class_name = 'Math' ) ORDER BY id
Saat menjalankan query di atas, kita dapat melihat bahwa hanya baris Alice yang dipilih:
| id | first_name | last_name | |----|------------|-----------| | 1 | Alice | Smith |
Kueri luar memilih
student
kolom baris yang ingin kami kembalikan ke klien. Namun, klausa WHERE menggunakan operator EXISTS dengan subkueri bagian dalam yang terkait.Operator EXISTS mengembalikan nilai true jika subkueri mengembalikan setidaknya satu record dan false jika tidak ada baris yang dipilih. Mesin database tidak harus menjalankan subquery seluruhnya. Jika satu rekaman cocok, operator EXISTS mengembalikan nilai true, dan baris kueri terkait lainnya dipilih.
Subkueri bagian dalam berkorelasi karena kolom student_id dari
student_grade
tabel cocok dengan kolom id dari tabel mahasiswa luar.sumber
EXIST
hanya berfungsi dengan subkueri berkorelasi? Saya bermain-main dengan query yang hanya berisi 1 tabel, sepertiSELECT id FROM student WHERE EXISTS (SELECT 1 FROM student WHERE student.id > 1)
. Saya tahu apa yang saya tulis dapat dicapai dengan satu kueri WHERE sederhana tetapi saya hanya menggunakannya untuk memahami ADA. Saya mendapatkan semua baris. Apakah memang karena saya tidak menggunakan subkueri berkorelasi? Terima kasih.EXISTS berarti subkueri mengembalikan setidaknya satu baris, itu benar-benar. Dalam kasus tersebut, ini adalah subkueri yang berkorelasi karena memeriksa supplier_id dari tabel luar ke supplier_id dari tabel dalam. Kueri ini sebenarnya mengatakan:
PILIH semua pemasok Untuk setiap ID pemasok, lihat apakah ada pesanan untuk pemasok ini Jika pemasok tidak ada di tabel pesanan, hapus pemasok dari hasil KEMBALIKAN semua pemasok yang memiliki baris yang sesuai di tabel pesanan
Anda dapat melakukan hal yang sama dalam kasus ini dengan INNER JOIN.
SELECT suppliers.* FROM suppliers INNER JOIN orders ON suppliers.supplier_id = orders.supplier_id;
Komentar kuda poni benar. Anda perlu melakukan pengelompokan dengan gabungan itu, atau memilih berbeda tergantung pada data yang Anda butuhkan.
sumber
Apa yang Anda gambarkan adalah apa yang disebut kueri dengan subkueri berkorelasi .
(Secara umum) itu adalah sesuatu yang harus Anda coba hindari dengan menulis kueri dengan menggunakan gabungan sebagai gantinya:
SELECT suppliers.* FROM suppliers JOIN orders USING supplier_id GROUP BY suppliers.supplier_id
Karena jika tidak, subkueri akan dieksekusi untuk setiap baris di kueri luar.
sumber
orders
yang cocok dengan kondisi penggabungan.