Question

I have a simple tag table in Postgres 9.3:

CREATE TABLE tag (
  id SERIAL PRIMARY KEY,
  text TEXT NOT NULL UNIQUE
);

Currently I can insert a new tag and get back the new id easily enough:

INSERT INTO tag (text) VALUES ('hey') RETURNING id

However I would like to check that the tag doesn't already exist (unique constraint) and if it does exist, return the id of the existing tag.

I attempted to use COALESCE to achieve this:

SELECT COALESCE(
    (SELECT id FROM tag WHERE text='hey'),
    (INSERT INTO tag (text) VALUES ('hey') RETURNING id)
)

But unfortunately while I believe this logic is sound it doesn't look like I can have an INSERT statement in a COALESCE (generates a syntax error at INTO).

What's the easiest way to accomplish this?

Was it helpful?

Solution 2

Credit goes to Clodoaldo Neto for his answer.

I'm putting my answer here because while his answer did point me in the direction it is slightly different, and I've simplified mine a bit.

WITH 
    existing AS (SELECT id FROM tag WHERE text='hey'),
    new AS (INSERT INTO tag (text) SELECT 'hey' WHERE NOT EXISTS (SELECT 1 FROM existing) RETURNING id)

SELECT id FROM existing UNION ALL SELECT id FROM new

OTHER TIPS

This should give you the same result. If the row doesn't exist, then create it. After that part executes, the row will definitely exist and we select its id.

IF NOT EXISTS (SELECT id FROM tag WHERE text = 'hey')
BEGIN
    INSERT INTO tag (text) VALUES ('hey')
END
SELECT id FROM tag WHERE text = 'hey'
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top