PostgreSQL foreign key

前端之家收集整理的这篇文章主要介绍了PostgreSQL foreign key前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

什么是外键?

外键就是用来关联表的节点,是为了保持表的参照完整性。一个表中的外键必须能够在另外一个关系表中能够匹配到.

官方文档中的例子为例:

假如现在有一个订单表,需要确保订单order里面的商品在product里面存在,这里我们就需要在order增加一个外键这个外键就是product表里面的主键

createtableproduct(
	product_noserialconstraintproduct_pkeyprimarykey,nametext,otherscharactervarying(100)
);

上面这个例子创建了一个product表,主键是product_no 主键的名字是product_pkey

下面创建一个orders表,外键是product_no,参照product表中的product_no

createtableorders(
order_noserialprimarykey,product_nointegerreferencesproduct(product_no),otherscharactervarying(100)
);

当创建之后,如果你在order表里面插入一条数据,而所插入的product_no的在product表里面没没有就会出现报错

ERROR:insertorupdateontable"orders"violatesforeignkeyconstraint"orders_product_no_fkey"
DETAIL:Key(product_no)=(1)isnotpresentintable"product".


回到这里

createtableorders(
	order_noserialprimarykey,product_nointeger,nameintegerreferencesproduct,otherscharactervarying(100)
);

当我们执行上面一句的时候也是可以通过的,即使外键约束的字段和被引用表的字段不同,只要与参照表主键的数据类型一样就可以了。但是这里并不是很推荐,不方便以后的维护。

在上面这个例子里面提到了一种不同的写法:

createtableorders(
order_noserialprimarykey,product_nointegerreferencesproduct,otherscharactervarying(100)
);

上面这种写法,当缺少字段列表的时候,系统会自动引用被引用表的主键作为order表的外键

但是它不能像创建主键一样写成下面这种方式:

createtableorders(
order_noserialprimarykey,product_nointegerforeignkey,nameinteger,otherscharactervarying(100)
);

这样会报错

外键也能够像检查约束一样,把一个字段组创建为一个外键,例如:

createtablet1(
aintegerprimarykey,binteger,cinteger,FOREIGNKEY(b,c)REFERENCESt2(b,c)
);

不过执行上面这条sql之前你需要先执行下面这条,不然没有引用表,说t2不存在:

createtablet2(
	aintegerprimarykey,unique(b,c)
);

执行完上面这条语句之后就会创建一个组外键。说到这儿可以发现外键不一定是被引用表中的主键,只要外键的字段在被引用表的字段拥有唯一约束就可以。

一个表里面可以创建多个外键,这种实现的原因是为了实现多对多的一种关系,假如你的订单表order有多个商品:

-----------producttable
createtableproduct(
	product_noserialprimarykey,nametext
);
-----------orderstable
createtableorders(
	order_noserialprimarykey,shippingtext
);
------------relationshiptable
createtableorder_item(
	order_nointegerreferencesorders,detailtext,primarykey(product_no,order_no)
);

最后的关系表order_item:外键和主键是重叠的。在标准里面是允许的。

在生产环境中经常有这样的情况:当创建了某个上面的订单,而在未来的某一刻,商品表中的某个商品被删除了呢?

上面那种情况是不能删除的,你只有把order_item表里面在product有关系的数据删除才能够删除product表中的数据,但是想删除

-----------producttable
createtableproduct(
	product_noserialprimarykey,shippingtext
);
------------relationshiptable
createtableorder_item(
	order_nointegerreferencesordersondeleterestrict,product_nointegerreferencesproductondeletecascade,order_no)
);

上面的这段语句,restrict与cascade分别是限制级联

限制的意思是当在关联表里面存在被引用表的值,则不允许删除

级联的意思是当关联表里面存在被引用表的值,假如删除被引用表的值,那么关联表中的数据也会随之删除

系统默认是restrict

除了上面两个常用的选项之外,为了业务逻辑的考虑有的为了保留数据。还有set null与set default。set default必须保证默认值能够拥有关联性,能够起到外键的效果。不然就会抛出错误,上面的例子中就不可以设置为default,但是你可以设置为null,但是设置为null也会出现问题,就是被引用表的字段数据也是NULL,如果这样就会造成数据混乱的问题。在这里建议在设置关联字段的时候,把它设置为not null。

与ON delete与之对应的还有ON UPDATE。数据更新也是一样的。

对于删除与更新操作,都会扫描关联表的整个表。例如上面的那个例子,当删除product表中的某一条数据的时候,它会扫描整个关联表order_item。所以在这里你需要创建一个索引。以便能够快速扫描。

原文链接:https://www.f2er.com/postgresql/195393.html

猜你在找的Postgre SQL相关文章