Bu sorgu neden çalışıyor?


37

Oracle 12c'de diyelim ki iki tablo var, table_a (id, name) ve table_b (id).

Bu sorgu neden bir istisna döndürmüyor?

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

Anladığım kadarıyla, Oracle bunu görüyor

select * from table_a where name = name;

Ama anlamadığım şey neden?

Yanıtlar:


61

table_bBir namesütun olmasa bile sorgu sözdizimsel olarak doğru SQL'dir . Sebebi kapsam çözümlemesidir.

Sorgu ayrıştırıldığında, önce table_bbir namesütunun olup olmadığı kontrol edilir . Olmadığından, o table_azaman kontrol edilir. Yalnızca tabloların hiçbirinde namesütun yoksa, bir hata verir .

Sonunda sorgu şu şekilde yürütülür:

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

Sorgunun vereceği sonuçlara gelince, her satır table_aiçin alt sorgu (select name from table_b)- veya (select a.name from table_b b)- aynı a.namedeğerde ve aynı sayıda satır içeren tek bir sütuna sahip bir tablodur table_b. Bu nedenle, table_b1 veya daha fazla satır varsa, sorgu şu şekilde çalışır:

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

veya:

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

veya:

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

Eğer table_bboş, sorgu (thnx için @ughai ihtimalini işaret için) hiçbir satır döndürür.


Bu (bir hata alamadığınız gerçeği) muhtemelen tüm sütun referanslarının tablo adı / takma adıyla birlikte ön eklenmesi gerektiğinin en iyi nedenidir. Eğer sorgu:

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

hatayı hemen alırdınız. Tablo önekleri ihmal edildiğinde, bu tür hataların, özellikle daha karmaşık sorgularda ve daha da önemlisi, fark edilmeden yapılması zor değildir.

Oracle belgelerinde de okuyun : Statik SQL İfadelerinde Adların Çözümü İç yakalamada benzer örnek B-6 ve SELECT ve DML İfadeleri paragraflarında İç Yakalamayı Önlemek'deki tavsiyeler :

İfadedeki her sütun referansını uygun tablo diğer adıyla nitelendirin.


SQL motorun iç işleyişini bu kadar doğru bir şekilde nasıl parçaladınız?
RinkyPinku

8

Çünkü

Oracle, iç içe geçmiş bir alt sorgu, alt sorgudan bir seviye üstteki ana ifadeye başvuruda bulunan bir tablodan bir sütuna başvurduğunda ilişkili bir alt sorgu gerçekleştirir. http://docs.oracle.com/cd/E11882_01/server.112/e41084/queries007.htm#SQLRF52357

Alt sorgunun ilişkili olup olmadığını belirlemek için Oracle , dış deyim bağlamı da dahil olmak üzere alt sorgudaki adları çözümlemeye çalışmalıdır. Ve nameönceden düzeltilmemiş için mümkün olan tek çözünürlük.


4

nameAlan yok , table_bbu yüzden Oracle ondan alıyor table_a. Denedim EXPLAIN PLANama bu bana sadece bir tane olduğunu verdi TABLE ACCESS FULL. Bunun, her iki tablonun arasında bir isim Kartezyen Ürün üreteceğini varsayarım, tüm isimlerin bir listesi table_aalt sorguyla döndürülür.


5
"Table_b'da ad alanı yok, bu yüzden Oracle tablo_a'dan birini alıyor." Doğru. “Bunun bir tür Kartezyen Ürün üreteceğini tahmin ediyorum.” Yanlış. Sorgu var from table_a where .... Boş table_aolanların dışındaki tüm satırları döndürür name.
ypercubeᵀᴹ

1
TABLE ACCESS FULLSadece Oracle'ın sıralı bir tarama yaptığını söyleme şekli.
Joishi Bodio

1
PLANINIZ önemsiz - büyük tablolarla indeksleme olabilir - test verilerinde çalıştığını farz ediyorum?
Vérace
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.