Postgres 对行组的唯一约束
Postgres unique constraint on groups of rows
我正在使用 postgresql 10.12
我已经标记了实体。有些是标准的,有些不是。标准实体由所有用户共享,而非标准实体由用户拥有。假设我有一个 table Entity
和一个文本列 Label
,以及一个对于标准实体为空的列 user_id
。
CREATE TABLE Entity
(
id uuid NOT NULL PRIMARY KEY,
user_id integer,
label text NOT NULL,
)
这是我的约束:属于不同用户的两个非标准实体可以具有相同的标签。标准实体标签是唯一的,给定用户的实体具有唯一标签。困难的部分是:标签在一组标准实体 + 给定用户的实体中必须是唯一的。
我正在使用 sqlAlchemy,这是我到目前为止所做的约束:
__table_args__ = (
UniqueConstraint("label", "user_id", name="_entity_label_user_uc"),
db.Index(
"_entity_standard_label_uc",
label,
user_id.is_(None),
unique=True,
postgresql_where=(user_id.is_(None)),
),
)
我对这个约束的问题是我不保证用户实体不会有标准实体标签。
示例:
+----+---------+------------+
| id | user_id | label |
+----+---------+------------+
| 1 | null | std_ent |
| 2 | 42 | user_ent_1 |
| 3 | 42 | user_ent_2 |
| 4 | 43 | user_ent_1 |
+----+---------+------------+
这是有效的 table。我想确保无法再创建带有标签 std_ent
的实体,用户 42 无法创建另一个带有标签 user_ent_1
或 user_ent_2
的实体,并且用户 43 无法创建另一个实体标签为 user_ent_1
.
的实体
在我目前的限制下,用户 42 和 43 仍然可以创建带有标签 std_ent
的实体,这就是我想要修复的问题。
有什么想法吗?
如果您的唯一约束正在阻止用户为他们自己的“用户实体”输入重复标签,那么您可以通过添加触发器来阻止他们输入“标准实体”的标签。
您创建了一个函数……
CREATE OR REPLACE FUNCTION public.std_label_check()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
begin
if exists(
select * from entity
where label = new.label and user_id is null) then
raise exception '"%" is already a standard entity', new.label;
end if;
return new;
end;
$function$
;
... 然后将其作为触发器附加到 table
CREATE TRIGGER entity_std_label_check
BEFORE INSERT
ON public.entity FOR EACH ROW
EXECUTE PROCEDURE std_label_check()
我正在使用 postgresql 10.12
我已经标记了实体。有些是标准的,有些不是。标准实体由所有用户共享,而非标准实体由用户拥有。假设我有一个 table Entity
和一个文本列 Label
,以及一个对于标准实体为空的列 user_id
。
CREATE TABLE Entity
(
id uuid NOT NULL PRIMARY KEY,
user_id integer,
label text NOT NULL,
)
这是我的约束:属于不同用户的两个非标准实体可以具有相同的标签。标准实体标签是唯一的,给定用户的实体具有唯一标签。困难的部分是:标签在一组标准实体 + 给定用户的实体中必须是唯一的。
我正在使用 sqlAlchemy,这是我到目前为止所做的约束:
__table_args__ = (
UniqueConstraint("label", "user_id", name="_entity_label_user_uc"),
db.Index(
"_entity_standard_label_uc",
label,
user_id.is_(None),
unique=True,
postgresql_where=(user_id.is_(None)),
),
)
我对这个约束的问题是我不保证用户实体不会有标准实体标签。
示例:
+----+---------+------------+
| id | user_id | label |
+----+---------+------------+
| 1 | null | std_ent |
| 2 | 42 | user_ent_1 |
| 3 | 42 | user_ent_2 |
| 4 | 43 | user_ent_1 |
+----+---------+------------+
这是有效的 table。我想确保无法再创建带有标签 std_ent
的实体,用户 42 无法创建另一个带有标签 user_ent_1
或 user_ent_2
的实体,并且用户 43 无法创建另一个实体标签为 user_ent_1
.
在我目前的限制下,用户 42 和 43 仍然可以创建带有标签 std_ent
的实体,这就是我想要修复的问题。
有什么想法吗?
如果您的唯一约束正在阻止用户为他们自己的“用户实体”输入重复标签,那么您可以通过添加触发器来阻止他们输入“标准实体”的标签。
您创建了一个函数……
CREATE OR REPLACE FUNCTION public.std_label_check()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
begin
if exists(
select * from entity
where label = new.label and user_id is null) then
raise exception '"%" is already a standard entity', new.label;
end if;
return new;
end;
$function$
;
... 然后将其作为触发器附加到 table
CREATE TRIGGER entity_std_label_check
BEFORE INSERT
ON public.entity FOR EACH ROW
EXECUTE PROCEDURE std_label_check()