简体   繁体   English

如何为表的行子集创建外键约束?

[英]how to create a Foreign-Key constraint to a subset of the rows of a table?

I have a reference table, say OrderType that collects different types of orders: 我有一个参考表,比如OrderType ,它收集不同类型的订单:

CREATE TABLE IF NOT EXISTS OrderType (name VARCHAR);
ALTER TABLE OrderType ADD PRIMARY KEY (name);
INSERT INTO OrderType(name) VALUES('sale-order-type-1');
INSERT INTO OrderType(name) VALUES('sale-order-type-2');
INSERT INTO OrderType(name) VALUES('buy-order-type-1');
INSERT INTO OrderType(name) VALUES('buy-order-type-2');

I wish to create a FK constraint from another table, say SaleInformation , pointing to that table ( OrderType ). 我希望从另一个表创建一个FK约束,比如SaleInformation ,指向该表( OrderType )。 However, I am trying to express that not all rows of OrderType are eligible for the purposes of that FK (it should only be sale-related order types). 但是,我试图表示并非所有OrderType符合FK的目的(它应该只是与销售相关的订单类型)。

I thought about creating a view of table OrderType with just the right kind of rows (view SaleOrderType ) and adding a FK constraint to that view, but PostgreSQL balks at that with: 我想到创建一个表OrderType的视图,只有正确的行(查看SaleOrderType )并向该视图添加一个FK约束,但PostgreSQL在那里使用:

ERROR: referenced relation "SaleOrderType" is not a table 

So it seems I am unable to create a FK constraint to a view (why?). 所以我似乎无法为视图创建FK约束(为什么?)。 Am I only left with the option of creating a redundant table to hold the sale-related order types? 我是否只选择创建一个冗余表来保存与销售相关的订单类型? The alternative would be to simply allow the FK to point to the original table, but then I am not really expressing the constraint as strictly as I would like to. 另一种方法是简单地允许FK指向原始表,但是我并没有像我想的那样严格地表达约束。

I think your schema should be something like this 我认为你的架构应该是这样的

create table order_nature (
    nature_id int primary key,
    description text
);
insert into order_nature (nature_id, description)
values (1, 'sale'), (2, 'buy')
;

create table order_type (
    type_id int primary key,
    description text
);
insert into order_type (type_id, description)
values (1, 'type 1'), (2, 'type 2')
;

create table order_nature_type (
    nature_id int references order_nature (nature_id),
    type_id int references order_type (type_id),
    primary key (nature_id, type_id)
);

insert into order_nature_type (nature_id, type_id)
values (1, 1), (1, 2), (2, 1), (2, 2)
;

create table sale_information (
    nature_id int default 1 check (nature_id = 1),
    type_id int,
    foreign key (nature_id, type_id) references order_nature_type (nature_id, type_id)
);

If the foreign key clause would also accept an expression the sale information could omit the nature_id column 如果foreign key子句也接受表达式,则销售信息可以省略nature_id列

create table sale_information (
    type_id int,
    foreign key (1, type_id) references order_nature_type (nature_id, type_id)
);

Notice the 1 in the foreign key 注意foreign key1

You could use an FK to OrderType to ensure referential integrity and a separate CHECK constraint to limit the order types. 您可以使用FK to OrderType来确保参照完整性,并使用单独的CHECK约束来限制订单类型。

If your OrderType values really are that structured then a simple CHECK like this would suffice: 如果您的OrderType值确实是那种结构,那么像这样的简单CHECK就足够了:

check (c ~ '^sale-order-type-')

where c is order type column in SaleInformation 其中cSaleInformation订单类型列

If the types aren't structured that way in reality, then you could add some sort of type flag to OrderType (say a boolean is_sales column), write a function which uses that flag to determine if an order type is a sales order: 如果类型实际上没有这样构造,那么你可以为OrderType添加某种类型的标志(比如一个布尔的is_sales列),写一个使用该标志的函数来确定订单类型是否是销售订单:

create or replace function is_sales_order_type(text ot) returns boolean as $$
    select exists (select 1 from OrderType where name = ot and is_sales);
$$ language sql

and then use that in your CHECK: 然后在你的CHECK中使用它:

check(is_sales_order_type(c))

You don't of course have to use a boolean is_sales flag, you could have more structure than that, is_sales is just for illustrative purposes. 你当然不必使用boolean is_sales标志,你可以有更多的结构, is_sales只是为了说明的目的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM