Create two tables with some ids overlapping.
create table outer_table (
id integer,
overlap_in smallint default 0
);
create table inner_table (
inner_id integer
);
Next, populate them with ids, some common.
insert into outer_table(id) values 0, 1, 2, 3, 4, 5, 6, 7, 8, 9;
insert into inner_table(inner_id) values 0, 1, 2;
Next, update the overlap indicator. BUT, by mistake, you type in the wrong column name, you write just "id" instead of "inner_id", and you decide not to use an alias.
update outer_table o
set o.overlap_in = 1
where o.id in (select id from inner_table);
The result:
How is this even normal? Any explanations why db2 allows this?
Note: DB2 Version:
>db2level
DB21085I Instance "....." uses "64" bits and DB2 code release "SQL09075"
with level identifier "08060107".
Informational tokens are "DB2 v9.7.0.5", "...", "IP23285", and Fix Pack
"5".
This is normal, expected behavior. As in most every programming language, identifiers are resolved this way in SQL. If an identifier does not exist in the innermost scope, name resolution works outward. If there is no column named "id" in the innermost scope, the column name is resolved outside that scope. Here, "id" is resolved as o.id. You should always use table prefixes!
Suppose you had written
where exists (
select * from inner_table
where inner_table.inner_id = id
)
You would certainly want the identifier "id" to be resolved as o.id, just like it is in your example. It would be silly if within a subquery, you could not refer to columns from other tables in the query.
That said, it would also be nice if some SQL implementations could do sanity checks that flagged queries like this, because if there is only one column mentioned in a subquery with a FROM clause, it usually should be a column from the table in the subquery. If not, it's typically a typo (but still a legal query).