Skip site navigation (1) Skip section navigation (2)

Re: Inserting into table only if the row does not already exist.

From: Greg Stark <gsstark(at)mit(dot)edu>
To: "C(dot) Bensend" <benny(at)bennyvision(dot)com>
Cc: pgsql-sql(at)postgresql(dot)org
Subject: Re: Inserting into table only if the row does not already exist.
Date: 2004-10-15 05:10:50
Message-ID: 87hdow4ld1.fsf@stark.xeocode.com (view raw or flat)
Thread:
Lists: pgsql-sql
"C. Bensend" <benny(at)bennyvision(dot)com> writes:

> INSERT INTO table ( column1, column2, column3 )
>    SELECT column1, column2, column3
>    WHERE NOT EXISTS (
>       SELECT column1, column2, column3 FROM table WHERE
>          column1 = $column1 AND
>          column2 = $column2 AND
>          column3 = $column3 )
> 
>    .. which gave me 'ERROR: column1 does not exist'.  Nuts.

Well you're not selecting from any table so "column1" isn't going to exist.
You just have to put it in the select list as a constant. If you're feeling
generous to the next programmer to read it you could put "AS column1" after
each one, but the column name doesn't actually have to match the column you're
inserting into.

 INSERT INTO table ( column1, column2, column3 )
   (
    SELECT $column1, $column2, $column3
     WHERE NOT EXISTS (
       SELECT 1
         FROM table 
        WHERE column1 = $column1
          AND column2 = $column2
          AND column3 = $column3 )
    )

Note that this is going to have some concurrency issues. I think it will be
possible for a second query to execute before the first commits. In that case
it won't see the record the first query inserted and try to insert again.
You'll just get a primary key violation though which I guess you can just
ignore.

Which raises a question. Why not forgoe this complicated SQL and try to do the
insert. If you get a primary key violation, well there's your answer... If you
don't care about the failure just ignore it and move on. I would suggest
checking specifically for a primary key violation and still stopping execution
on unexpected errors though.

If you're doing this inside a bigger transaction that's a bit more of a pain.
Until 8.0 postgres can't handle ignoring an error on a query without aborting
the entire transaction. But if you're in autocommit mode then you can just
ignore the primary key violation and continue. 

Incidentally, if you're putting your parameters directly into your queries
using $column1 then you've got a potential security problem. Unless you're
quoting every variable everywhere religiously using postgres's quoting
functions an attacker can sneak extra SQL into your queries. Potentially
including whole new statements such as "DELETE FROM table"...

-- 
greg


In response to

Responses

pgsql-sql by date

Next:From: Christoph HallerDate: 2004-10-15 08:57:18
Subject: Re: libpq-fe: PQgetvalue() ?
Previous:From: C. BensendDate: 2004-10-15 04:18:21
Subject: Inserting into table only if the row does not already exist.

Privacy Policy | About PostgreSQL
Copyright © 1996-2014 The PostgreSQL Global Development Group