Apakah subquery menambah daya ekspresif ke kueri SQL?

29

Apakah SQL memerlukan subquery?

Bayangkan implementasi yang cukup umum dari bahasa query terstruktur untuk database relasi. Karena struktur SELECTpernyataan SQL kanonik sebenarnya cukup penting untuk membuat ini masuk akal, saya tidak menarik langsung ke aljabar relasional, tetapi Anda bisa membingkai ini dalam istilah-istilah tersebut dengan membuat batasan yang tepat pada bentuk ekspresi.

SQL SELECTpermintaan umumnya terdiri dari proyeksi (yang SELECTbagian) beberapa jumlah JOINoperasi (yang JOINbagian), beberapa jumlah SELECTION operasi (di SQL, WHEREklausa), dan kemudian set-bijaksana operasi ( UNION, EXCEPT, INTERSECT, dll), diikuti oleh yang lain SELECTPermintaan SQL .

Tabel yang disatukan dapat berupa hasil ekspresi yang dikomputasi; dengan kata lain, kita dapat memiliki pernyataan seperti:

SELECT t1.name, t2.address
  FROM table1 AS t1 
  JOIN (SELECT id, address 
          FROM table2 AS t3 
         WHERE t3.id = t1.id) AS t2
 WHERE t1.salary > 50,000;

Kami akan merujuk pada penggunaan tabel yang dihitung sebagai bagian dari kueri SQL sebagai subquery. Dalam contoh di atas, yang kedua (indentasi) SELECTadalah subquery.

Bisakah semua query SQL ditulis sedemikian rupa agar tidak menggunakan subquery? Contoh di atas dapat:

SELECT t1.name, t2.address
  FROM table1 AS t1 
  JOIN table2 AS t2
    ON t1.id = t2.id
 WHERE t1.salary > 50,000;

Contoh ini agak palsu, atau sepele, tetapi orang dapat membayangkan contoh-contoh di mana upaya yang jauh lebih mungkin diperlukan untuk memulihkan ekspresi yang setara. Dengan kata lain, apakah itu kasus untuk setiap query SQL dengan subqueries, ada query tanpa subqueries sehingga dan dijamin untuk menghasilkan hasil yang sama untuk tabel dasar yang sama? Biarkan kami membatasi kueri SQL ke formulir berikut:q q q qqqq

SELECT <attribute>,
      ...,
      <attribute>
 FROM <a table, not a subquery>
 JOIN <a table, not a subquery>
  ...
 JOIN <a table, not a subquery>
WHERE <condition>
  AND <condition>
  ...
  AND <condition>

UNION
 -or-
EXCEPT
 -or-
<similar>

SELECT ...

Dan seterusnya. Saya pikir gabungan luar kiri dan kanan tidak menambahkan banyak, tetapi jika saya salah, silakan tunjukkan ... dalam hal apa pun, mereka juga merupakan permainan yang adil. Sejauh operasi ditetapkan, saya kira salah satu dari mereka baik-baik saja ... penyatuan, perbedaan, perbedaan simetris, persimpangan, dll ... apa pun yang bermanfaat. Apakah ada bentuk yang diketahui dimana semua pertanyaan SQL dapat dikurangi? Apakah ada di antara ini yang menghilangkan subkueri? Atau ada beberapa contoh di mana tidak ada kueri yang setara dan bebas subquery? Referensi dihargai ... atau demonstrasi (dengan bukti) bahwa mereka diperlukan atau tidak diperlukan akan fantastis. Terima kasih, dan maaf jika ini adalah hasil yang dirayakan (atau sepele) yang saya sangat tidak tahu.

Patrick87
sumber
5
Naluri saya memberi tahu saya bahwa Anda selalu dapat menggabungkan semuanya dan memilih dari sana selama Anda tidak perlu nilai gabungan. Memilih semua entri dengan nilai yang lebih besar dari rata-rata kolomnya tampaknya memerlukan komputasi averge terlebih dahulu, oleh karena itu memerlukan subquery.
Raphael
@Raphael Saya cukup yakin Anda bahkan dapat melakukan nilai agregat, Anda hanya perlu melakukan lebih banyak self-joins dan group-bys (membuatnya secara eksponensial lebih besar, tetapi masih memungkinkan). Namun, tidak yakin bagaimana saya membuktikan secara resmi Anda bisa melakukan semuanya dengan cara itu.
Kevin
@Kevin Apakah Anda yakin jumlah operasi yang diperlukan tidak tergantung pada jumlah baris? Karena kita tidak dapat memilikinya, bukan?
Raphael
1
Contoh normal saya miliki untuk yang membutuhkan subquery mengandalkan duplikat: select count(*) from (select id from sometable group by id having count(*)>1) d. Karena itu termasuk group bysaya belum menempatkan ini sebagai jawaban.
Mark Hurd
BTW AFAIK dalam SQL normal ONklausa diperlukan untuk JOINs, meskipun produk silang diperoleh hanya dengan koma.
Mark Hurd

Jawaban:

9

Ada beberapa kebingungan terminologi; blok permintaan dalam tanda kurung

SELECT t1.name, t2.address
  FROM table1 
  JOIN (SELECT id, address 
          FROM table2 AS t3 
         WHERE t3.id = t1.id) 

disebut pandangan dalam . Sebuah subquery adalah blok permintaan dalam salah MANA atau klausa SELECT, misalnya

select deptno from dept
where 3 < (select count(1) from emp 
           where dept.deptno=emp.deptno)

Dalam kedua kasus tersebut, pandangan bagian dalam atau subquery dapat digabungkan ke dalam proyek "flat" -rote-join. Subquery yang terkait dengan agregasi membuat unests ke tampilan dalam dengan pengelompokan, yang kemudian memasukkan ke dalam query datar.

select deptno from dept d
    where 3 < (select avg(sal) from emp e
               where d.deptno=e.deptno)

select d.deptno from dept d, ( 
    select deptno from emp e
    group by deptno
    having avg(sal) > 3
) where d.deptno=e.deptno

select d.deptno from dept d, emp e
where d.deptno=e.deptno 
group by d.deptno
having avg(sal) > 3

Adapun aturan aljabar untuk optimisasi kueri, aljabar relasional diketahui di aksioma menjadi Relational Lattice yang menyederhanakan transformasi kueri seperti yang ditunjukkan di sana - sini .

Tegiri Nenashi
sumber
Saya penasaran. Bisakah Anda menambahkan contoh kueri yang menggunakan beberapa bidang rata-rata, misalnya memilih semua entri dengan nilai rata-rata di atas? Tidak jelas bagi saya bagaimana itu akan terlihat setelah rata.
Raphael
16

Untuk menerjemahkan pernyataan Anda ke aljabar relasional, saya pikir itu bertanya:

σSEBUAH(SEBUAH)σB(B)σSEBUAH(σB(SEBUAHB))

σ

Jawabannya adalah "Ya," dan ini merupakan optimasi kueri standar. Sejujurnya, saya tidak yakin bagaimana membuktikan ini dengan cara yang tidak meminta pertanyaan - itu hanya properti pilihan dan bergabung. Anda dapat berdebat secara induktif untuk menambahkan berapa pun lapisan kueri bersarang yang diinginkan.

Selain itu, Anda mungkin bertanya:

SEBUAHBC...(SEBUAHB)(CD)

Sekali lagi jawabannya adalah ya, karena bergabung adalah asosiatif. Pernyataan serupa dapat dibuat tentang proyeksi juga.

Salah satu jenis "subquery" yang menurut saya tidak bisa "diratakan" adalah with. Salah satu cara untuk melihatnya adalah dengan mencatat bahwa jika Anda memiliki withpernyataan maka Anda dapat memiliki fungsi rekursif, yang tidak dapat ditulis tanpa menggunakan subquery.

Jadi kesimpulannya: dalam kasus spesifik yang Anda sebutkan, tidak, SQL tidak perlu subquery, dan Anda dapat membuktikannya secara induktif. Secara umum, ada beberapa fitur yang memerlukan subquery.

Xodarap
sumber
Perilaku rekursif via withdiperkenalkan di SQL: 1999, dan membuat bahasa yang dihasilkan lebih ekspresif.
András Salamon
1

"Apakah subqueries menambah kekuatan ekspresif ke query SQL?"

Mereka melakukannya, setidaknya sebelum pengenalan KECUALI dalam bahasa SQL.

Sebelum pengenalan KECUALI, tidak ada cara apa pun untuk mengekspresikan perbedaan relasional atau semi-perbedaan dalam SQL tanpa menggunakan subqueries.

Saat ini, semua operator primitif "khas" aljabar relasional "dapat diekspresikan tanpa subqueries:

GABUNG ALAM dapat dilakukan melalui GABUNG ALAMI, atau GABUNG PADA
UNION dapat dilakukan melalui UNION.
MINUS dapat dilakukan melalui KECUALI
PROYEK / RENAME / PERBAIKAN dapat dilakukan melalui SELECT
RESTRICT dapat dilakukan melalui WHERE
relational literal dapat dilakukan melalui VALUES
penutupan dapat dilakukan melalui VALUES. dapat dilakukan melalui DENGAN rekursif

Erwin Smout
sumber