2

I'm running PostgreSQL 10 and have several BEFORE INSERT OR UPDATE and AFTER INSERT OR UPDATE on my table tests.

I want to have another trigger BEFORE INSERT OR UPDATE which should check for potential duplicate row.

I've made this:

CREATE OR REPLACE FUNCTION set_check_dublicate_on_test() RETURNS trigger AS $$
    BEGIN
        IF EXISTS (SELECT 1 FROM tests WHERE test_id = NEW.test_id) THEN
            RETURN NULL;
        ELSE
            RETURN NEW;
        END IF;

    END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS set_check_dublicate_on_test ON tests;
CREATE TRIGGER set_check_dublicate_on_test BEFORE INSERT OR UPDATE ON tests
    FOR EACH ROW EXECUTE PROCEDURE set_check_dublicate_on_test();

But I'm not sure if it will conflict with other triggers or it will fullfill the goal, and the triggers simply will be ignored if this returns NULL ?

4
  • Isn't it easier to check on duplicate values using a unique index on test_id ? Commented Jul 15, 2019 at 8:58
  • Create a unique index on test_id then use insert ... on conflict (test_id) do nothing - no trigger required. And it will even work with concurrent inserts of the same value (which the trigger will not be able to detect) Commented Jul 15, 2019 at 8:58
  • I do allow test_id to be NULL, which should allow insert - would this still work? Commented Jul 15, 2019 at 9:06
  • @Alfred Valid remark but apparently it should still work: see stackoverflow.com/questions/23449207/…) Commented Jul 15, 2019 at 12:21

2 Answers 2

4

Firstly - I believe that if you want to have a unique field in your table - then it is the easiest to mark it as such:

https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-UNIQUE-CONSTRAINTS

If an attempted insert on such a field should not raise an error, then there is a the ON CONFLICT keyword:

https://www.postgresql.org/docs/current/sql-insert.html

Especially: ON CONFLICT DO NOTHING

Sign up to request clarification or add additional context in comments.

5 Comments

I do allow test_id to be NULL, which should allow insert - would this still work?
In general, a unique constraint is violated if there is more than one row in the table where the values of all of the columns included in the constraint are equal. However, two null values are never considered equal in this comparison. That means even in the presence of a unique constraint it is possible to store duplicate rows that contain a null value in at least one of the constrained columns. This behavior conforms to the SQL standard, but we have heard that other SQL databases might not follow this rule. So be careful when developing applications that are intended to be portable.
If test_id ist the only column in the unique constraint - Postgresql will allow NULL values.
I'll accept this as it was the first solution. THank you all.
@AlfredBalle what if you already have duplicate data in your column an you want the new entries to now unique without deleteing the old data? I think a trigger would apply there
1

Let the database manage uniqueness! This ensures data integrity for both inserts and updates.

This is quite simple:

alter table test add constraint unq_test_test_id unique (test_id);

If you insert rows one at a time, then this is fine. The insert (or update) will fail.

If you want to insert multiple rows and allow non-duplicate inserts to go in, then us on conflict:

insert into test ( . . . )
    select . ..
    from . . .
    on conflict on constraint unq_test_test_id do nothing;

1 Comment

Would ON CONFLICT (test_id) DO UPDATE SET test_id = test_id also work as sort of upsert ? As I'm getting error in my application with DO NOTHING because it exepcts to return id of inserted row.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.