PG Bug reporting form <noreply@postgresql.org> writes:
> This will throw an error that the column does not exist:
> ```
> WITH to_delete AS (
> SELECT MIN(id), username
> FROM test
> GROUP BY username
> HAVING count(*) > 1
> )
> SELECT id
> FROM to_delete;
> ```
Sure, because the columns exposed by to_delete are named "min" and
"username", not "id".
> However, the this will not return an error and instead deletes all rows:
> ```
> WITH to_delete AS (
> SELECT MIN(id), username
> FROM test
> GROUP BY username
> HAVING count(*) > 1
> )
> DELETE FROM test
> WHERE id IN (
> SELECT id
> FROM to_delete
> );
> ```
You've been bit by the standard SQL newbie trap that sub-selects
allow outer references. That IN clause devolves to constant true
(at least for non-null id values, and with to_delete known not
empty), because it's just "id = id".
regards, tom lane