PostgreSQL - 基于另一个列的约束 Table
PostgreSQL - Constraint Based on Column in Another Table
我有两个table,一个叫ballots,一个叫votes。选票存储代表人们可以投票的选项的字符串列表:
CREATE TABLE IF NOT EXISTS Polls (
id SERIAL PRIMARY KEY,
options text[]
);
Votes 存储用户投票(其中投票是一个整数,表示他们投票的选项的索引):
CREATE TABLE IF NOT EXISTS Votes (
id SERIAL PRIMARY KEY,
poll_id integer references Polls(id),
value integer NOT NULL ,
cast_by integer NOT NULL
);
我想确保每当在投票 table 中创建一行时,'value' 的值在民意调查中相应行的 [0,length(options)) 范围内(通过对应,我指的是 poll_id 匹配的行)。
我可以实施任何类型的检查或外键约束来完成此任务吗?或者我需要某种触发器吗?如果是这样,触发器会是什么样子,会不会有性能问题?使用 SELECT 语句手动查询相应的民意调查,然后断言 'value' 在插入 Votes table 之前有效,是否同样高效?
在您的要求中,您不能使用检查约束,因为它可以引用相同的列 table。
同样可以参考官方Manual。
所以,在这里你应该在 Votes
Table 的 BEFORE INSERT
事件上使用触发器,或者你可以使用 function/procedure(取决于你的 PostgreSQL 版本)插入操作,您可以在插入之前检查值,如果条件不满足则引发异常。
正在使用触发器:
create or replace function id_exist() returns trigger as
$$
begin
if new.value<0 or new.value>=(select array_length(options,1) from polls where id=new.poll_id) then
raise exception 'value is not in range';
end if;
return new;
end;
$$
language plpgsql
CREATE TRIGGER check_value BEFORE INSERT ON votes
FOR EACH ROW EXECUTE PROCEDURE id_exist();
我建议您将数据模型修改为 table、PollOptions
:
CREATE TABLE IF NOT EXISTS PollOptions (
PollOptionsId SERIAL PRIMARY KEY, -- should use generated always as identity
PollId INT NOT NULL, REFERENCES Polls(id),
OptionNumber int,
Option text,
UNIQUE (PollId, Option)
);
那么你的 Votes
table 应该有一个指向 PollOptions
的外键引用。您可以使用 PollOptionId
或 (PollId, Option)
.
如果正确设置数据,则不需要触发器或特殊函数。
我有两个table,一个叫ballots,一个叫votes。选票存储代表人们可以投票的选项的字符串列表:
CREATE TABLE IF NOT EXISTS Polls (
id SERIAL PRIMARY KEY,
options text[]
);
Votes 存储用户投票(其中投票是一个整数,表示他们投票的选项的索引):
CREATE TABLE IF NOT EXISTS Votes (
id SERIAL PRIMARY KEY,
poll_id integer references Polls(id),
value integer NOT NULL ,
cast_by integer NOT NULL
);
我想确保每当在投票 table 中创建一行时,'value' 的值在民意调查中相应行的 [0,length(options)) 范围内(通过对应,我指的是 poll_id 匹配的行)。
我可以实施任何类型的检查或外键约束来完成此任务吗?或者我需要某种触发器吗?如果是这样,触发器会是什么样子,会不会有性能问题?使用 SELECT 语句手动查询相应的民意调查,然后断言 'value' 在插入 Votes table 之前有效,是否同样高效?
在您的要求中,您不能使用检查约束,因为它可以引用相同的列 table。
同样可以参考官方Manual。
所以,在这里你应该在 Votes
Table 的 BEFORE INSERT
事件上使用触发器,或者你可以使用 function/procedure(取决于你的 PostgreSQL 版本)插入操作,您可以在插入之前检查值,如果条件不满足则引发异常。
正在使用触发器:
create or replace function id_exist() returns trigger as
$$
begin
if new.value<0 or new.value>=(select array_length(options,1) from polls where id=new.poll_id) then
raise exception 'value is not in range';
end if;
return new;
end;
$$
language plpgsql
CREATE TRIGGER check_value BEFORE INSERT ON votes
FOR EACH ROW EXECUTE PROCEDURE id_exist();
我建议您将数据模型修改为 table、PollOptions
:
CREATE TABLE IF NOT EXISTS PollOptions (
PollOptionsId SERIAL PRIMARY KEY, -- should use generated always as identity
PollId INT NOT NULL, REFERENCES Polls(id),
OptionNumber int,
Option text,
UNIQUE (PollId, Option)
);
那么你的 Votes
table 应该有一个指向 PollOptions
的外键引用。您可以使用 PollOptionId
或 (PollId, Option)
.
如果正确设置数据,则不需要触发器或特殊函数。