PostgreSQL foreign key

什么是外键?

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

官方文档中的例子为例:

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

create table product(
	product_no  serial constraint product_pkey primary key  ,
	name text,
	others character varying(100)
);

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

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

create table orders(
    order_no serial primary key,
    product_no integer references product (product_no) ,
    name text,
    others character varying(100)
);

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

ERROR:  insert or update on table "orders" violates foreign key constraint "orders_product_no_fkey"
DETAIL:  Key (product_no)=(1) is not present in table "product".


回到这里

create table orders(
	order_no serial primary key,
	product_no integer ,
	name integer references product,
	others character varying(100)
);

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

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

create table orders(
    order_no serial primary key,
    product_no integer  references product,
    name text ,
    others character varying(100)
);

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

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

create table orders(
    order_no serial primary key,
    product_no integer foreign key,
    name integer,
    others character varying(100)
);

这样会报错

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

create table t1(
    a integer primary key,
    b integer,
    c integer,
    FOREIGN KEY (b, c)  REFERENCES t2(b,c)
);

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

create table t2(
	a integer primary key,
	b integer,
	c integer,
	unique (b,c)
);

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

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

-----------product table
create table product(
	product_no serial    primary key,
	name text
);
-----------orders table
create table orders(
	order_no serial primary key,
	shipping text
);
------------relationship table
create table order_item(
	order_no integer references orders,
	product_no integer references product,
	detail text,
	primary key (product_no,order_no)
);

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

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

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

-----------product table
create table product(
	product_no serial    primary key,
	name text
);
-----------orders table
create table orders(
	order_no serial primary key,
	shipping text
);
------------relationship table
create table order_item(
	order_no integer references orders on delete restrict,
	product_no integer references product on delete cascade,
	detail text,
	primary key (product_no,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://my.oschina.net/websec/blog/371578

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值