Question

I have a table similar to this:

CREATE TABLE orders(
    order_id UUID PRIMARY KEY,
    owner_id TEXT,
    other_data TEXT
)

I am trying to do an insert-or-update type of operation on the database. The logic I am trying to implement is as:

  1. If a record already exists with the given order_id, and the given owner_id matches, then update the record
  2. else, if a record already exists with the given order_id, and the given owner_id does not match, then throw an error
  3. Otherwise, insert a new record

Ideally I would like to implement it as a stored procedure using the custom UPSERT example in the postgresql docs as an example.

The problem I have struck is distinguishing between case 1. and case 2. above, without having to do two separate queries. If I do this:

UPDATE orders(other_data) WHERE order_id=order_id_param AND owner_id=owner_id_param;

then if no orders are matched I will not know if it is because the record did not exist, or it did exist but the owner_id did not match.

Of course I could do an initial query like this before the update:

SELECT count(1) FROM orders WHERE order_id=order_id_param AND owner_id!=owner_id_param;

and throw an error if the returned count>0; but I'd like to avoid the extra query if it is possible.

I am using PostgreSQL 9.2.

I found this similar SO question but it was for SQL Server 2008 and didn't seem to solve it in a way I could simply apply to PostgreSQL.

Was it helpful?

Solution

In the end I solved this by defining a trigger which prevents UPDATE queries on the table from succeeding if the owner_id does not match.

It's dead simple and looks something like this:

CREATE OR REPLACE FUNCTION order_update_check() 
RETURNS trigger
AS $$
BEGIN
    IF NEW.owner_id != OLD.owner_id THEN
        RAISE EXCEPTION 'User % cannot modify order %', NEW.owning_user, OLD.order_id;
    END IF;
    RETURN NEW;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER order_update_trigger BEFORE UPDATE ON orders
    FOR EACH ROW EXECUTE PROCEDURE order_update_check();

Having defined this, I then defined an upsert procedure much the same as described in the PG docs.

Thanks to @Noran for giving me the idea.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top