专栏内容:
- postgresql内核源码分析
- 手写数据库toadb
- 并发编程
个人主页:我的主页
管理社区:开源数据库
座右铭:天行健,君子以自强不息;地势坤,君子以厚德载物.
在数据库中,数据类型可以限制数据存储的大小,也能在一定程度上限制存储的数据种类,但是对于数据库应用来讲,它太宽泛了,比如有些表示人名的字段,就不能为空,货物数量的字段,不能为负值,这与实际生活符合,而数据类型并不能做这些约束,这就需要数据库提供一套更贴近应用,或者说与现实世界更符合的规则,来约束数据的有效性。
数据库的约束是一种规则,用于限制或规范数据库中的数据,确保数据的完整性和一致性。这些约束可以定义在表级别或列级别,处理机制是一致的。约束不占用任何数据库空间,而是存在于数据字典中,并在执行SQL期间使用。用户可以指明约束是启用的还是禁用的,当约束启用时,它增强了数据的完整性。
postgresql数据库中的约束类型主要包括以下几种:
这些约束在数据库设计中起着至关重要的作用,它们有助于维护数据的准确性和一致性,防止无效数据的插入和更新。
在表的列上指定一列或几列的组合,创建主键,这一列或列的组合就称为主键列,主键列上的所有行的数据不能重复,同时主键列的值不能为空。
在每个表上只能最多有一个主键。
建议在每张表上都创建一个主键,因为在建立主键的同时,数据库会自动在主键列上创建索引,叫做主键索引,它可以加束通过主键的查找或者修改数据。
下面列举几创建主键的SQL语法有几种形式。
CREATE TABLE table_name ( column1 data_type PRIMARY KEY, column2 data_type, … );
CREATE TABLE table_name ( column_1 data_type, column_2 data_type, column_3 data_type, … PRIMARY KEY(column_1, column2, ...) );
不管是主键列有一列或者多列,两种写法都可以使用。
当我们的表已经创建完成时,或者数据已经导入,此时发现需要增加一个主键,那么可以通过修改表定义的方式来添加主键,SQL语法如下:
ALTER TABLE table_name ADD PRIMARY KEY (column_1, column_2, ...);
当然这个操作需要有表的alter权限。
有创建主键,就可以删除主键,删除主键约束的SQL语法如下:
ALTER TABLE table_name DROP CONSTRAINT primary_key_constraint_name;
其中primary_key_constraint_name是主键约束的名称,在上面的创建方法中,我们并没有指定主键约束的名称,数据库会自动为我们增加主键约束的名称,在删除之前需要通过\d命令来查看一下表的定义,示例如下:
postgres=# \d products Table "public.products" Column | Type | Collation | Nullable | Default --------------+------------------------+-----------+----------+--------- product_id | integer | | not null | product_name | character varying(255) | | not null | price | numeric(10,2) | | not null | category | character varying(255) | | | Indexes: "products_pkey" PRIMARY KEY, btree (product_id) Referenced by: TABLE "orders" CONSTRAINT "orders_product_id_fkey" FOREIGN KEY (product_id) REFERENCES products(product_id) postgres=#
products表在product_id列上有一个主键,名称为products_pkey,因为它同时会创建索引,所以在索引分类中。
注意,这里有可能会被别的表以外键方式引用,就会删除失败,此时的处理方法请看下一节外键约束。
当定义一张表时,期望其中一列的数据与另一张表的某一列的数据一致时,就需要用到外键约束,比如定单表中的产品ID列,就需要与产品表中的产品ID列一致,不能出现产品表中没有的产品ID。
外键约束是指一列或几列的值,与另一张表的对应的一列或几列出现的值相匹配,我们说这两张相关表保持了引用完整性。
注意外键通过引用另一张表的唯一能标识行的一列或一组列的值来建立引用关系,所以被引用的列必须是主键的列。当然,引用与被引用的列的类型是必须相同的,也就是它们有相同的值范围。
外键约束的定义SQL语法,同样也有几种。
CREATE TABLE table_name1 ( column11 data_type , column12 data_type REFERENCES table_name2 (column21), … );
在需要定义引用完整性的列定义后面,使用references关键字,再加被引用的表外与列名即可。
另一种是放在表定义的最后,可以指定单列或多列的引用完整性。
CREATE TABLE table_name1 ( column11 data_type , column12 data_type , … FOREIGN KEY (column11, column12) REFERENCES table_name2 (column21, column22) );
放在表定义后部时,需要使用foreign key关键字开头来指定本表需要引用的字段。
当数据表创建完成后,可以通过修改表的定义来完成外键的添加;
ALTER TABLE table_name1 ADD CONSTRAINT foreign_key_constraint_name FOREIGN KEY (column11 ...) REFERENCES table_name2 (column22 ...);
这里可以是单列,或者多列组的引用。
当不需要外键约束时,可以删除表上某个外键,外键约束的名称通过查看表定义来获得,在命令行客户端上通过\d tablename命令查看。
ALTER TABLE table_name1 DROP CONSTRAINT foreign_key_constraint_name;
除了引用另一张表之外,还可以引用自身表的列,这也是非常有用的一种写法。
CREATE TABLE tree ( node_id integer PRIMARY KEY, parent_id integer REFERENCES tree, name text, ... );
因为外键是引用另一张表,当被引用表发生变动时,也会影响引用表,也就是外键表。
一般会发生两类变动:
假如一个订单表的产品ID列引用产品表的ID列,那么会存在这样一个情况,产品不再有效时,会从产品表中删除,那么此时订单表中已经产生的此产品的订单将会如何处理呢?
可能是,不让它删除,这在一些应用中也是如此处理,另外会加一个是否删除的字段;或者把订单表中引用此产口ID的订单一起删除,这看起来不是很好;一起来看看数据库中提供了那些可选项。
在定义外键时,可以指定它的引用数据发生变动时,可以执行的动作,语法如下:
CREATE TABLE table_name1 ( column11 data_type , column12 data_type , … FOREIGN KEY (column11, column12) REFERENCES table_name2 ON DELETE [action] (column21, column22) );
还可以是,
CREATE TABLE table_name1 ( column11 data_type , column12 data_type , … FOREIGN KEY (column11, column12) REFERENCES table_name2 ON UPDATE [action] (column21, column22) );
因为被引用表的数据有删除或更新两种情况,在这两种情况下引用表需要指定动作,其中的action可以用以下动作代替:
这部分我们将在单独的一个章节点来分享。
与数据变动有类似的问题,被引用表删除时或者主键删除时,引用表如何处理呢?
在postgresql中,会阻止被引用表的删除,必须先解除引用,或者先删除引用表,这里提供了一个cascade选项,可以级联删除引用表。
postgres=# \d order_items Table "test1.order_items" Column | Type | Collation | Nullable | Default ------------+---------+-----------+----------+--------- product_no | integer | | | order_id | integer | | | quantity | integer | | | Foreign-key constraints: "order_items_order_id_fkey" FOREIGN KEY (order_id) REFERENCES orders(order_id) "order_items_product_no_fkey" FOREIGN KEY (product_no) REFERENCES products(product_no)
查看一下外键关系,可以看到order_items同时引用了orders和products两张表的列,下面选择将products表删除,并指定级联删除选项;
postgres=# drop table products cascade ; NOTICE: drop cascades to constraint order_items_product_no_fkey on table order_items DROP TABLE postgres=# \d List of relations Schema | Name | Type | Owner --------+-------------+-------+-------- test1 | order_items | table | zpzhao test1 | orders | table | zpzhao (2 rows)
可以看到删除表的同时会自动将引用关系解除,删除了order_items表上对products表的外键引用。
本文主要分享了表的约束分类中的主键和外键两类,它们对数据的数据的实体完整性和参照完整性都会起到约束作用,当然在使用过程中要熟悉它们的SQL语法,以及它们的特性。
非常感谢大家的支持,在浏览的同时别忘了留下您宝贵的评论,如果觉得值得鼓励,请点赞,收藏,我会更加努力!
作者邮箱:study@senllang.onaliyun.com
如有错误或者疏漏欢迎指出,互相学习。
注:未经同意,不得转载!