例:
我有:
Table A:
int id
int table_b_id
Table B:
int id
text type
我想在列table_b_id上添加一个约束检查,以验证它是否仅指向表B中的行,其类型值为' X'。
我无法改变桌面结构
我已经明白可以通过“检查”来完成这项工作。和postgres函数将进行特定的查询,但我看到人们建议避免它
任何关于实施它的最佳方法的输入都会有所帮助。
答案 0 :(得分:0)
你所指的不是FOREIGN KEY
,它在PostgreSQL中是指另一个表中的(一些)列,其中该列/那些列上有唯一索引(s ),当那些/那些列的值发生变化时,可能会有相关的自动操作(ON UPDATE
,ON DELETE
)。
您正在尝试强制执行特定类型的引用完整性,类似于FOREIGN KEY
所执行的操作。您可以使用CHECK
子句和函数执行此操作(因为CHECK
子句不允许子查询),您也可以使用table inheritance and range partitioning执行此操作(请参阅子表,仅保留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';
答案 1 :(得分:0)
在我看来,最优雅的解决方案是使用inheritance来获取子类型行为:
PostgreSQL 9.3 Schema Setup with inheritance:
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_id)=(2)" b_x"。
从基表中检索所有数据:
select * from B
<强> Results 强>:
| id |
|----|
| 2 |
| 1 |
检索类型为的数据:
SELECT p.relname, c.*
FROM B c inner join pg_class p on c.tableoid = p.oid
<强> Results 强>:
| relname | id |
|---------|----|
| b | 2 |
| b_x | 1 |