Mengapa kueri ini berfungsi?


37

Saya punya dua tabel, table_a (id, nama) dan table_b (id), katakanlah pada Oracle 12c.

Mengapa kueri ini tidak mengembalikan pengecualian?

select * from table_a where name in (select name from table_b);

Dari apa yang saya mengerti, Oracle melihat ini sebagai

select * from table_a where name = name;

Tapi yang tidak saya dapatkan adalah mengapa?

Jawaban:


61

Kueri secara sintaksis adalah SQL, bahkan jika table_btidak memiliki namekolom. Alasannya adalah resolusi ruang lingkup.

Ketika kueri diuraikan, pertama-tama diperiksa apakah table_bmemiliki namekolom. Karena tidak, maka table_adiperiksa. Itu akan menimbulkan kesalahan hanya jika tabel tidak memiliki namekolom.

Akhirnya kueri dijalankan sebagai:

select a.* 
from table_a  a
where a.name in (select a.name 
                 from table_b  b
                );

Adapun hasil kueri akan memberikan, untuk setiap baris table_a, subquery (select name from table_b)- atau (select a.name from table_b b)- adalah tabel dengan satu kolom dengan nilai yang sama a.namedan baris sebanyak table_b. Jadi, jika table_bmemiliki 1 baris atau lebih, kueri berjalan sebagai:

select a.* 
from table_a  a
where a.name in (a.name, a.name, ..., a.name) ;

atau:

select a.* 
from table_a  a
where a.name = a.name ;

atau:

select a.* 
from table_a  a
where a.name is not null ;

Jika table_bkosong, kueri tidak akan mengembalikan baris (thnx ke @ughai untuk menunjukkan kemungkinan itu).


Itu (fakta bahwa Anda tidak mendapatkan kesalahan) mungkin adalah alasan terbaik bahwa semua referensi kolom harus diawali dengan nama tabel / alias. Jika kueri adalah:

select a.* from table_a where a.name in (select b.name from table_b); 

Anda akan langsung mendapat kesalahan. Ketika awalan tabel dihilangkan, tidak sulit untuk kesalahan tersebut terjadi, terutama dalam permintaan yang lebih kompleks, dan bahkan yang lebih penting, tidak diperhatikan.

Baca juga di Oracle docs: Resolusi Nama dalam Pernyataan SQL Statis , contoh serupa B-6 dalam tangkapan dalam dan rekomendasi dalam paragraf Menghindari Penangkapan Dalam di paragraf SELECT dan DML Statement :

Kualifikasi setiap referensi kolom dalam pernyataan dengan alias tabel yang sesuai.


Bagaimana Anda membedah cara kerja mesin SQL secara akurat?
RinkyPinku

8

Karena

Oracle melakukan subquery berkorelasi ketika subquery bersarang referensi kolom dari tabel yang merujuk ke pernyataan induk satu tingkat di atas subquery. http://docs.oracle.com/cd/E11882_01/server.112/e41084/queries007.htm#SQLRF52357

Itu berarti untuk menentukan apakah subquery berkorelasi Oracle harus mencoba untuk menyelesaikan nama dalam subquery termasuk konteks pernyataan luar juga. Dan untuk yang tidak diperbaiki nameitu satu-satunya resolusi yang mungkin.


4

Tidak ada namebidang dalam table_bsehingga Oracle mengambil satu dari table_a. Saya mencoba EXPLAIN PLANtetapi ini memberi saya hanya ada TABLE ACCESS FULL. Saya berasumsi bahwa ini akan menghasilkan semacam Produk Cartesian antara kedua tabel yang menghasilkan daftar semua nama table_ayang dikembalikan oleh sub-kueri.


5
"Tidak ada bidang nama di table_b sehingga Oracle mengambil satu dari table_a." Benar. "Saya kira ini akan menghasilkan semacam Produk Cartesian." Salah. Kueri memiliki from table_a where .... Ini akan mengembalikan semua baris table_akecuali yang namenol.
ypercubeᵀᴹ

1
TABLE ACCESS FULLhanyalah cara Oracle untuk memberi tahu Anda bahwa ia melakukan pemindaian berurutan.
Joishi Bodio

1
RENCANA Anda tidak relevan - mungkin ada pengindeksan dengan tabel besar - Saya berasumsi bahwa Anda menjalankan data uji?
Vérace
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.