示例:
我有:
Table A:
int id
int table_b_id
Table B:
int id
text type
我想在 table_b_id 列上添加一个约束检查,以验证它是否仅指向表 B 中类型值为“X”的行。
我无法更改表结构。
我知道可以使用“CHECK”和一个 postgres 函数来完成特定的查询,但我看到人们建议避免使用它。
关于什么是实施它的最佳方法的任何输入都会有所帮助。
示例:
我有:
Table A:
int id
int table_b_id
Table B:
int id
text type
我想在 table_b_id 列上添加一个约束检查,以验证它是否仅指向表 B 中类型值为“X”的行。
我无法更改表结构。
我知道可以使用“CHECK”和一个 postgres 函数来完成特定的查询,但我看到人们建议避免使用它。
关于什么是实施它的最佳方法的任何输入都会有所帮助。
您所指的不是 a FOREIGN KEY
,在 PostgreSQL 中,它指的是另一个表中的一个(多个)列,其中该列/那些列上有一个唯一索引,并且可能具有关联的自动当那个/那些列的值改变时的动作(ON UPDATE
, ON DELETE
)。
您正在尝试强制执行特定类型的引用完整性,类似于 aFOREIGN KEY
所做的。您可以使用CHECK
子句和函数来执行此操作(因为该CHECK
子句不允许子查询),您也可以使用表继承和范围分区来执行此操作(请参阅仅包含行 where 的子表type = 'X'
),但这可能是使用触发器最容易做到这一点:
CREATE FUNCTION trf_test_type_x() RETURNS trigger AS $$
BEGIN
PERFORM * FROM tableB WHERE id = NEW.table_b_id AND type = 'X';
IF NOT FOUND THEN
-- RAISE NOTICE 'Foreign key violation...';
RETURN NULL;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE tr_test_type_x
BEFORE INSERT OR UPDATE ON tableA
FOR EACH ROW EXECUTE PROCEDURE trf_test_type_x();
您可以创建一个部分索引tableB
来加快速度:
CREATE UNIQUE INDEX idx_type_X ON tableB(id) WHERE type = 'X';
在我看来,最优雅的解决方案是使用继承来获得子类型行为:
create table B ( id int primary key );
-- Instead to create a 'type' field, inherit from B for
-- each type with custom properties:
create table B_X ( -- some_data varchar(10 ),
constraint pk primary key (id)
) inherits (B);
-- Sample data:
insert into B_X (id) values ( 1 );
insert into B (id) values ( 2 );
-- Now, instead to reference B, you should reference B_X:
create table A ( id int primary key, B_id int references B_X(id) );
-- Here it is:
insert into A values ( 1, 1 );
--Inserting wrong values will causes violation:
insert into A values ( 2, 2 );
错误:在表“a”上插入或更新违反了外键约束“a_b_id_fkey”详细信息:表“b_x”中不存在键 (b_id)=(2)。
从基表中检索所有数据:
select * from B
结果:
| id |
|----|
| 2 |
| 1 |
检索类型为 的数据:
SELECT p.relname, c.*
FROM B c inner join pg_class p on c.tableoid = p.oid
结果:
| relname | id |
|---------|----|
| b | 2 |
| b_x | 1 |