Reputation: 661
I have two versions of PostgreSQL (8.0.4 / 8.1.4) and have noticed that in 8.1.4 I get a "Missing From-Clause Error" for the following statement:
DELETE FROM MDFUSERGROUPREL_DELETED
WHERE userid = MDFUSERGROUPREL.userid
AND usergroupid = MDFUSERGROUPREL.usergroupid
AND userid=?
As you cannot do a DELETE with SELECT statement in 8.0.4 I am using a direct table reference instead, but this seems to be causing a problem in 8.1.4
Is anyone able to confirm this behaviour and if possible provide a work around?
I know the versions i am using are old and not supported this is a environmental constraint so no I can't just upgrade it.
Upvotes: 3
Views: 2690
Reputation: 324951
You're relying on a behaviour of old versions of PostgreSQL which used to implicitly add FROM
clauses when tables were referenced that weren't listed in FROM
. You'll be able to see this in an EXPLAIN
of your query.
This misfeature was removed from PostgreSQL. It caused accidental cross-products on typos and was generally a very bad idea. You can re-enable it as a temporary workaround by setting the add_missing_from
configuration parameter to true either with a SET
statement before the problem query or in postgresql.conf
. This backwards compatibility workaround was removed in 9.0, so you cannot use it to get your app working with 9.0 or above. I've intentionally linked to the 8.4 version of the documentation because the parameter was removed from later versions.
See this mailing list discussion.
The cause of the problem in this query is that you're doing an implicit join on MDFUSERGROUPREL
. You should be naming this table explicitly in your USING
clause in the DELETE
statement.
Here's a demo showing the problem and workaround: http://sqlfiddle.com/#!11/6c4b3/4 ... and here's a demo showing how to do it correctly two different ways: http://sqlfiddle.com/#!11/6c4b3/7 . The 1st is a simple fix that just adds the missing from clause to the query and fixes the resulting column name conflicts:
DELETE FROM MDFUSERGROUPREL_DELETED
USING MDFUSERGROUPREL
WHERE MDFUSERGROUPREL_DELETED.userid = MDFUSERGROUPREL.userid
AND MDFUSERGROUPREL_DELETED.usergroupid = MDFUSERGROUPREL.usergroupid
AND MDFUSERGROUPREL_DELETED.userid=1;
You will find that the latter two examples result in the same query plan at least on modern versions of PostgreSQL, so it doesn't make a difference whether you use EXISTS
or a join.
I've followed your query's original style in not using table aliases, but I strongly suggest that you do use aliases for readability. See @wildplasser's example.
Upvotes: 4
Reputation: 44250
Not understanding your exact intentions, it still appears to me that exists
might do the trick:
DELETE FROM MDFUSERGROUPREL_DELETED del
WHERE EXISTS (SELECT *
FROM MDFUSERGROUPRE ex
WHERE ex.userid = del.userid
AND ex.usergroupid = del.usergroupid
)
AND del.userid=?
;
Upvotes: 2