1

示例:
我有:

Table A:  
 int id  
 int table_b_id

Table B:  
 int id  
 text type  

我想在 table_b_id 列上添加一个约束检查,以验证它是否仅指向表 B 中类型值为“X”的行。
我无法更改表结构。
我知道可以使用“CHECK”和一个 postgres 函数来完成特定的查询,但我看到人们建议避免使用它。
关于什么是实施它的最佳方法的任何输入都会有所帮助。

4

2 回答 2

1

您所指的不是 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';
于 2015-09-22T07:11:43.673 回答
0

在我看来,最优雅的解决方案是使用继承来获得子类型行为:

PostgreSQL 9.3 架构设置与继承

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 |
于 2015-09-22T07:50:05.013 回答