Tại sao truy vấn này hoạt động?


37

Tôi có hai bảng, table_a (id, name) và table_b (id), giả sử trên Oracle 12c.

Tại sao truy vấn này không trả lại một ngoại lệ?

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

Từ những gì tôi hiểu, Oracle thấy điều này là

select * from table_a where name = name;

Nhưng những gì tôi không nhận được là tại sao?

Câu trả lời:


61

Truy vấn là SQL chính xác về mặt cú pháp ngay cả khi table_bkhông có namecột. Lý do là độ phân giải phạm vi.

Khi truy vấn được phân tích cú pháp, đầu tiên nó được kiểm tra xem table_bnamecột không. Vì nó không, sau đó table_ađược kiểm tra. Nó sẽ chỉ báo lỗi nếu cả hai bảng không có namecột.

Cuối cùng, truy vấn được thực hiện như sau:

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

Đối với các kết quả mà truy vấn sẽ đưa ra, đối với mỗi hàng table_a, truy vấn con (select name from table_b)- hoặc (select a.name from table_b b)- là một bảng có một cột có cùng a.namegiá trị và có nhiều hàng như table_b. Vì vậy, nếu table_bcó 1 hàng trở lên, truy vấn sẽ chạy như sau:

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

hoặc là:

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

hoặc là:

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

Nếu table_btrống, truy vấn sẽ không trả về hàng nào (thnx đến @ughai để chỉ khả năng đó).


Điều đó (thực tế là bạn không gặp lỗi) có lẽ là lý do tốt nhất mà tất cả các tham chiếu cột phải được thêm tiền tố với tên bảng / bí danh. Nếu truy vấn là:

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

bạn sẽ có lỗi ngay lập tức. Khi các tiền tố bảng được bỏ qua, không khó để xảy ra các lỗi như vậy, đặc biệt là trong các truy vấn phức tạp hơn và thậm chí quan trọng hơn, không được chú ý.

Đọc thêm trong các tài liệu của Oracle: Độ phân giải của các tên trong các câu lệnh SQL tĩnh , ví dụ tương tự B-6 trong chụp bên trong và các khuyến nghị trong việc tránh bắt trong trong các đoạn của câu lệnh CHỌN và DML :

Đủ điều kiện mỗi tham chiếu cột trong tuyên bố với bí danh bảng thích hợp.


Làm thế nào bạn phân tích hoạt động bên trong của công cụ SQL chính xác như vậy?
RinkyPinku

8

Bởi vì

Oracle thực hiện một truy vấn con tương quan khi một truy vấn con lồng nhau tham chiếu một cột từ một bảng được tham chiếu đến một câu lệnh cha một cấp trên truy vấn con. http://docs.oracle.com/cd/E11882_01/server.112/e41084/queries007.htmlm#QueryRF52357

Điều đó có nghĩa là để xác định xem truy vấn con có tương quan hay không, Oracle phải cố gắng giải quyết các tên trong truy vấn con bao gồm cả bối cảnh câu lệnh bên ngoài. Và đối với không được chuẩn bị, nameđó là độ phân giải duy nhất có thể.


4

Không có namelĩnh vực nào table_bnên Oracle lấy cái đó từ table_a. Tôi đã thử EXPLAIN PLANnhưng điều này chỉ cho tôi rằng có một TABLE ACCESS FULL. Tôi đoán rằng điều này sẽ tạo ra một số loại Sản phẩm của Cartesian giữa cả hai bảng dẫn đến một danh sách tất cả các tên trong table_ađược trả về bởi truy vấn phụ.


5
"Không có trường tên trong bảng_b vì vậy Oracle lấy tên từ bảng_a." Chính xác. "Tôi đoán rằng điều này sẽ tạo ra một số loại Sản phẩm của Cartesian." Sai rồi. Các truy vấn có from table_a where .... Nó sẽ trả về tất cả các hàng từ table_atrừ những hàng không namecó giá trị.
ypercubeᵀᴹ

1
TABLE ACCESS FULLchỉ là cách của Oracle để nói với bạn rằng nó đang thực hiện quét tuần tự.
Joishi Bodio

1
KẾ HOẠCH của bạn không liên quan - cũng có thể lập chỉ mục với các bảng lớn - Tôi cho rằng bạn đang chạy trên dữ liệu thử nghiệm?
Vérace
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.