I have two tables, table_a (id, name) and table_b (id), let's say on Oracle 12c.
Why does this query not return an exception?
select * from table_a where name in (select name from table_b);
From what I understand, Oracle sees this as
select * from table_a where name = name;
But what I don't get is why?
Best Answer
The query is syntactically correct SQL even if
table_b
does not have aname
column. The reason is scope resolution.When the query is parsed, it is first checked whether
table_b
has aname
column. Since it doesn't, thentable_a
is checked. It would throw an error only if neither of the tables had aname
column.Finally the query is executed as:
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 samea.name
value and as many rows astable_b
. So, iftable_b
has 1 or more rows, the query runs as:or:
or:
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:
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: