Why does this query work?

The query is syntactically correct SQL even if table_b does not have a name column. The reason is scope resolution.

When the query is parsed, it is first checked whether table_b has a name column. Since it doesn't, then table_a is checked. It would throw an error only if neither of the tables had a name column.

Finally the query is executed as:

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

As for the results the query would give, for every row of table_a, the subquery (select name from table_b) - or (select a.name from table_b b) - is a table with a single column with the same a.name value and as many rows as table_b. So, if table_b has 1 or more rows, the query runs as:

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

or:

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

or:

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

If table_b is empty, the query will return no rows (thnx to @ughai for pointing that possibility).


That (the fact that you don't get an error) is probably the best reason that all column references should be prefixed with the table name/alias. If the query was:

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

you would have got the error straight away. When table prefixes are omitted, it is not difficult for such mistakes to happen, especially in more complex queries, and even more important, go unnoticed.

Read also in Oracle docs: Resolution of Names in Static SQL Statements the similar example B-6 in Inner capture and the recommendations in the Avoiding Inner Capture in SELECT and DML Statements paragraphs:

Qualify each column reference in the statement with the appropriate table alias.


Because

Oracle performs a correlated subquery when a nested subquery references a column from a table referred to a parent statement one level above the subquery. http://docs.oracle.com/cd/E11882_01/server.112/e41084/queries007.htm#SQLRF52357

It means in order to determine whether subquery is correlated Oracle must try to resolve names in subquery including outer statement context too. And for unprefixed name it's the only resolution possible.


There is no name field in table_b so Oracle takes the one from table_a. I tried the EXPLAIN PLAN but this gave me only that there is a TABLE ACCESS FULL. I presume that this will generate some kind of Cartesian Product between both tables that result in a list of all the names in table_a is returned by the sub-query.