我想在列value
中添加唯一键,但我必须忽略列value
和header_id
中具有相同值的行。例如,请考虑此表:
id | header_id | value
1 | 1 | a
2 | 1 | a
3 | 2 | a
因此,第1行和第2行指向同一个对象,唯一键应该接受它们,但第3行具有不同的header_id
(指向另一个对象),因为它具有与value
相同的value
对象1,它应该违反唯一约束并引发错误。
编辑16.2:1327:
我使用核心框架生成列来处理历史记录,因此我无法规范化表格。我的课程有很多专栏,但在本例中我只考虑{{1}}列。
答案 0 :(得分:3)
如果您可以稍微更改表格结构,则可以这样做:
your_table
id header_value
1 1
2 1
3 2
header_value
id header_id value
1 1 a
2 2 a
将your_table.header_value
的外键约束添加到header_value.id
。
现在,您可以在header_value.value
上添加唯一约束。
答案 1 :(得分:2)
您可以使用触发器模拟具有所需属性的唯一约束。像这样的东西可以解决这个问题:
create or replace function sort_of_unique() returns trigger as $$
declare
got_one boolean;
begin
select exists(
select 1
from your_table
where header_id != new.header_id
and value = new.value
) into got_one;
if got_one then
raise exception 'Uniqueness violation in your_table';
end if;
return new;
end;
$$ language plpgsql;
create trigger sort_of_unique_trigger
before insert or update on your_table
for each row execute procedure sort_of_unique();
然后你就会发生这样的事情:
=> insert into your_table (id, header_id, value) values (1, 1, 'a');
=> insert into your_table (id, header_id, value) values (2, 1, 'a');
=> insert into your_table (id, header_id, value) values (3, 2, 'a');
ERROR: Uniqueness violation in your_table
=> insert into your_table (id, header_id, value) values (3, 2, 'b');
=> update your_table set value = 'a' where id = 3;
ERROR: Uniqueness violation in your_table
您可以通过将WHERE子句附加到索引来创建partial unique indexes。这允许您将唯一性约束应用于表的切片;但是,我无法想办法让WHERE子句指定一个"反切片"所以我没有看到一种方法来使用部分索引来完成这项工作。我可能会遗漏一些明显的东西。
答案 2 :(得分:2)
过了一会儿我发现了什么。使用约束CHECK with function来确定是否存在(不能在CHECK语句中使用SELECT,但可以使用具有所需select的函数)
CREATE OR REPLACE FUNCTION is_value_free(_header_id integer, _value varchar) RETURNS BOOLEAN AS
$$
BEGIN
RETURN NOT EXISTS (SELECT header_id,value FROM myschema.mytalbe WHERE value LIKE _value AND header_id != _header_id LIMIT 1);
END;
$$ LANGUAGE plpgsql;
ALTER TABLE mytable ADD CONSTRAINT uniq_value CHECK (is_value_free(header_id,value))