'check if group-member allocation already exist

I have a schema that maps members to a group:

create table member (member_id serial, name varchar(10), primary key (member_id));
                    
create table groups (group_id serial, name varchar (10), primary key (group_id));

create table member_groups( 
  group_id integer, 
  member_id integer, 
  constraint fk_group foreign key (group_id) references groups(group_id), 
  constraint fk_member foreign key (member_id) references member(member_id)
);

How can I check if a group-member allocation already exists? e.g.:

insert into member (name) values('member 1'), ('member 2'), ('member 3'), ('member 4'), ('member 5');

insert into groups(name) values ('group 1'), ('group 2'), ('group 3');


insert into member_groups values (1, 1), (1,2), (1,4), (2,1), (2, 4);

another group with the same members, e.g. a group with members 1,2,4 like group 1 should not be allowed, a group with the members 1,2,3,4 should be allowed though. Probably this have to be checked by the application and could be not contrainted by the DDL (?).

DB-Fiddle



Solution 1:[1]

You can create a stored function set_members(group_id integer, members integer[]) to pass all the members in array and then do the validation inside the function. To validate you may use contains and contained by operators:

create function set_members(prm_group_id integer, prm_members integer[]) returns void
LANGUAGE plpgsql
SECURITY DEFINER
AS $fnk$
DECLARE
  _group integer;
BEGIN
  SELECT
    group_id
  INTO
    _group
  FROM 
    member_groups
  GROUP BY
    group_id
  HAVING 
    array_agg(member_id) @> prm_members
    AND array_agg(member_id) <@ prm_members
  LIMIT 1;
  
  IF FOUND THEN
    RAISE EXCEPTION 'Group with same members exists (id=%)', _group; 
  END IF;
  
  --insert members that are not included
  
  --your code here
  
  --delete no longer included members 
  
  --your code here
END
$fnk$;

To prevent inserting into member_groups directly you can use permissions allowing only the owner to insert and setting SECURITY DEFINER on the set_members function. That way it will be executed using permissions of the owner of the function.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Julius Tuskenis