Home > Mobile >  Postgres UNIQUE CONSTRAINT/INDEX for string array
Postgres UNIQUE CONSTRAINT/INDEX for string array

Time:12-31

I'm trying to prevent the user to insert more then 1 unique array of strings into the table.

I have created a Unique Constraint on the array: CONSTRAINT users_uniq UNIQUE(usersArray),

but the user can still insert the same values to the array but in a different order. My table:

id usersArray
1 {011,123}
2 {123,011} // should not be possible

Input : {011,123} --> error unique // the right error

Input : {123,011} --> Worked // Should have return an error instead

How can I make the value {123,011} and {011,123} considered the same?

CodePudding user response:

A trigger which enforces the order of the items in the array could be one approach. Here's an example:

The fiddle

CREATE TABLE test ( arr int ARRAY, unique (arr) );

CREATE FUNCTION test_insert_trig_func()
RETURNS trigger AS $$
BEGIN
    NEW.arr := ARRAY(SELECT unnest(NEW.arr) ORDER BY 1);
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER test_insert_trig
BEFORE INSERT ON test
FOR EACH ROW
EXECUTE PROCEDURE test_insert_trig_func()
;

INSERT INTO test VALUES ('{1, 2}');

INSERT INTO test VALUES ('{2, 1}');  -- Generates a unique constraint violation

SELECT * FROM test;

The result:

arr
{1,2}

CodePudding user response:

The trigger solution is not transparent as it is actually modifying the data. Here is an alternative. Create array_sort helper function (it might be useful for other cases too) and an unique index using it.

create or replace function array_sort (arr anyarray) returns anyarray immutable as 
$$
  select array_agg(x order by x) from unnest(arr) x;
$$ language sql;    

create table t (arr integer[]);
create unique index tuix on t (array_sort(arr));

Demo

insert into t values ('{1,2,3}'); -- OK
insert into t values ('{2,1,3}'); -- unique violation
select * from t;
arr
{1,2,3}
  • Related