Вы можете использовать массив для столбца, и "содержится в операторе" для ограничения CHECK:
create table pancakes (
color varchar(10)[] not null,
check (color <@ ARRAY['red', 'green', 'blue']::varchar[])
);
А потом происходят такие вещи:
=> insert into pancakes values (ARRAY['red']);
INSERT 0 1
=> insert into pancakes values (ARRAY['red','green','blue']);
INSERT 0 1
=> insert into pancakes values (ARRAY['red','green','blue','black']);
ERROR: new row for relation "pancakes" violates check constraint "pancakes_color_check"
=> select * from pancakes;
color
------------------
{red}
{red,green,blue}
(2 rows)
Это позволит {red,red}
в столбце; если важно запретить {red,red}
, вы можете добавить функцию для проверки уникальных значений цвета в массиве и настроить ограничение CHECK:
create function has_unique_colors(varchar[]) returns boolean as $$
select (select count(distinct c) from unnest($1) as dt(c)) = array_length($1, 1);
$$ language sql;
create table pancakes (
color varchar(10)[] not null,
check (color <@ ARRAY['red', 'green', 'blue']::varchar[] and has_unique_colors(color))
);
Другим вариантом будет набор таблиц ассоциаций с простыми скалярными значениями в столбцах. Тем не менее, это может быть громоздким, если у вас есть шесть из этих столбцов. Вы также можете использовать версию функции Эрвина, если вам нужно беспокоиться о NULL в «множествах»:
create function has_unique_colors(varchar[]) returns boolean as $$
select not exists(select c from unnest($1) dt(c) group by 1 having count(*) > 1);
$$ language sql;