![深入浅出PostgreSQL](https://wfqqreader-1252317822.image.myqcloud.com/cover/148/30573148/b_30573148.jpg)
3.5 创建数据表
在关系型数据库中,原始数据都存放在表中。本节将介绍如何创建表及表的存储属性。
3.5.1 创建表的语法格式
使用CREATE TABLE命令创建表,该命令比较复杂,语法格式如下:
格式1(创建表常规语法,如用于创建普通表或表分区中的父表)
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/54_6.jpg?sign=1739250815-Ik5p20y17A5kHX2K1D2UoX0DHZE2Su83-0-f836be4da7d26724f00e4f3b5ea15707)
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/55_1.jpg?sign=1739250815-KiXWKoCteCjXjaPAM2qUtMfXOYl6G6Fr-0-726abdc671a8257c16d54f6d4bad6bae)
格式2(根据类型名创建表)
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/55_2.jpg?sign=1739250815-avJWZJkRbCdD0Ng3HaZk9jd9ULols9zd-0-bee71b922e83697591b8f99a86899e3f)
格式3(用于创建表分区的分区)
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/55_3.jpg?sign=1739250815-GLVa2AWNnqqdqJC1AfVXLthviFEIMFef-0-46ea6c68198039f71c894b88032b18a1)
其中,column_constraint的定义如下。
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/55_4.jpg?sign=1739250815-PDEhRqJ3VzPeDXtywnDSAMiLRgfXLImz-0-ab856b10826b8444500876593cb67303)
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/56_1.jpg?sign=1739250815-F1UgjZI8QeDsf8OQ8nVX33jJeEJVSnI4-0-145a12984b57649d6616c627c66e035d)
table_constraint的定义如下。
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/56_2.jpg?sign=1739250815-pl2mNFc0PFjRRwWAOMRo9DdSGmFRRQky-0-b39ce37f3c5e52a71b5ba7d5e2b402a1)
like_option的定义如下。
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/56_3.jpg?sign=1739250815-DaJpWevJCYQTTbgzA9qJHOVZ31viiu3o-0-f6ee4f158348b24597832d90c602c234)
【举例】创建一个名为department的表,用来记录一个公司包含的部门信息。该表包含3个字段,deptid是部门的ID,deptname是部门的名称,createtime是部门的创建时间,代码如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/56_4.jpg?sign=1739250815-xnOnq03PDsKvvT9oW4jb1AhfvbkKhclz-0-25e308f7f1564f1bd57dc8f5f3ea3be8)
3.5.2 使用CHECK约束
CHECK约束是常见的约束类型。
1.简单的字段级CHECK约束
它用来约束一个特定列的值,使之满足一个Boolean类型表达式条件。
例如,在department表中,要求部门的创建时间必须在“1970-01-01 00:00:00”之后,即createtime字段的值必须大于“1970-01-01 00:00:00”,代码如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/57_1.jpg?sign=1739250815-bUawYnEi1C0y68fYA5QgJNxinxJvBOXM-0-e1853549425fe9149a116d74500c5ab4)
在上述代码中,CHECK约束在字段数据类型的后面,用CHECK作为标识,圆括号中是表达式的内容。
2.指定特定名字的字段级CHECK约束
用户还可以为CHECK约束指定一个特定的名字,这样可以清楚地识别出错信息,而且还可以根据需要修改约束条件,代码如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/57_2.jpg?sign=1739250815-YfxKJ5vErcPeR10Uz2jfnKMjVKdZRNtz-0-e98229fbcc0155912c25ccf170f2b863)
3.表级的CHECK约束
CHECK约束还可以涉及多个字段。例如,在department表中存在一个parentcreatetime字段,即该部门的上级部门的创建时间。要求,当前部门的创建时间需要小于其上级部门的创建时间,代码如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/57_3.jpg?sign=1739250815-cxCQQgHhn2tFO4aF0WuQ0L2pYIQhqegj-0-ed6ee411e26c130c812054177f146b50)
在上述代码中,前两个约束和字段定义放在一起,就是约束情景。第3个约束独立于表中的所有字段,单独放一行,称为表约束。
所有字段约束可以写成表约束的形式,但是有些表约束不能写成字段约束的形式。例如,上述实例中的表约束不可以转换成字段约束,因为涉及两个字段的比较,放到哪个字段的定义中都没办法描述。
例如,在“1.简单的字段级CHECK约束”中举例的字段约束可以转换成表约束,代码如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/58_1.jpg?sign=1739250815-T199xFalTRIDt60YBxXCfqM45RYicr8k-0-c26b647ae52d9545aca8924034615ed4)
3.5.3 使用非空约束
非空约束用于指定一个字段不能设置为NULL值。创建表的语法格式如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/58_2.jpg?sign=1739250815-sblgJZESG1dGZIazUueXRnB3NV4QY8Y3-0-d3d7f13bd1405d3d45db92b3c1396b54)
一个字段可能包含多个约束,这些约束的先后顺序没有特别要求,语法格式如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/58_3.jpg?sign=1739250815-CKaXyMIe4QkY3gpdOH0b5pETGqhs9NlK-0-98d2bc0cde09db3299deed6db35e6b4d)
在创建表语句中,如果没有显示指定一个字段为NOT NULL,则表明该字段可以取值为NULL。
3.5.4 使用唯一性约束
唯一性约束能够确保一个字段或几个字段的组合在整张表中是唯一的,语法格式如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/58_4.jpg?sign=1739250815-8UMquUxe5JaeHiXwTfs2uGCxdspdY0pZ-0-e8babf9fca7005459991b4838c1d7f7c)
上面语句将唯一性约束写成字段约束的形式,也可以写成表约束的形式,语法格式如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/58_5.jpg?sign=1739250815-FylfpzU37mZZaCxPj8mw06ykme3P1R1v-0-f35a2b5537d94c48cc0554434b1b20b8)
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/59_1.jpg?sign=1739250815-bZ4WGJa06BHKP1E3CtKUFkMSUOoUDQjN-0-69c28878d839e5167e54f6c951887e29)
唯一性约束也可以是多个字段的组合,语法格式如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/59_2.jpg?sign=1739250815-i9iWfoeT1gJkD232Q5yLLYnN9SyNQXTR-0-dd77bf4d9d1283f8ee89ec6011c37762)
唯一性约束在a、b两个字段上,这就要求a、b两个字段的组合取值在全表中是唯一的,但允许其中一个字段的值相同。
除在创建表时创建唯一性约束外,还可以在创建表之后,通过CREATE UNIQUE INDEX命令创建唯一性约束。
如果在一个已经有数据的表中创建唯一性约束,而这些唯一性约束对应的字段值相同,则创建唯一性约束失败。每一个UNIQUE约束默认都会创建一个唯一索引,有关创建唯一索引的语法在后续章节中会详细介绍。
3.5.5 使用主键约束
主键约束指定一个字段或几个字段的组合是唯一的。它与唯一性约束的差别是——要求将这些字段值设为NOT NULL。为了更好地说明,下面两个实例的效果是一样的,语法格式如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/59_3.jpg?sign=1739250815-xkNsFWgJWaFnOMUU654r8iFOQCuWe5TK-0-319af46de651b253c402765dc58afb95)
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/59_4.jpg?sign=1739250815-LmPyH2p9Zoua6nVq95pWlyDNMxMectHS-0-bfaa9370783849d4dcfd20468d0a3116)
与唯一性约束一样,主键约束也可以是多个字段的组合,语法格式如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/59_5.jpg?sign=1739250815-FSznxOdoeS3AfEONMzFwOuGkUFwoPCgw-0-f4463b64dfb18720730e9f705996711d)
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/60_1.jpg?sign=1739250815-fTuGGlVCVECNoevPsLIT7jLp1wVGw5PJ-0-73f50e33e75ba136cd5a669efd76de91)
提示:
一个表最多只能有一个主键,但可以有多个非空的唯一索引。
3.5.6 使用默认约束
在使用CREATE TABLE命令创建一个表时,可以为字段设置默认值。在插入一条语句时,如果没有给某些字段设置默认值,则会使用其定义的默认值。如果一个字段没有定义默认值,则将NULL作为其默认值。
使用默认值创建表的语法格式如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/60_3.jpg?sign=1739250815-qeGqJ4FCyNXwKhX0KkB0RJrPVWeWMqDh-0-7aba0c35994c7bed0306fe7b909d6ca0)
其中,DEFAULT为关键字,其后跟随默认值。一般将默认约束放在字段定义的后面。
默认值除可以是常量外,还可以是表达式。需要注意的是,该表达式的值是在插入语句时计算的,并不是创建表时计算的。
如果没有给createtime字段赋值,则在执行INSERT语句时调用CURRENT_TIMESTAMP()函数获取当前时间戳,语法格式如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/60_4.jpg?sign=1739250815-TiTPRlljXhyfQKg1sxhaAfnhauupes6r-0-8ec1d5a16ae4dfe2b999cf12143dfbf2)
3.5.7 使用外键约束
外键约束要求一个表对应字段(或多个字段组合)的值必须和另外一个表对应字段的值相同。外键约束用来实现参数完整性。
1.单字段的外键约束
前文我们一直引用的department表记录了一个公司的部门信息。现在我们引入另外一个表,即employee表,记录该公司的职员信息,代码如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/60_5.jpg?sign=1739250815-9AC9oZPprCFNFaImOcdShndNSs5iEF8r-0-002dc75b0a4c201b38856587534b5195)
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/61_1.jpg?sign=1739250815-y6USxoARiPDVWTQMMaJgdlwHW9Y1LJUd-0-1b2f5e88ebe3ffbc1c13318b942504d5)
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/61_2.jpg?sign=1739250815-2k3Ar5rey9cDmxcRoPIXeI96AA9FkMXN-0-15dab9c5b9b36c27af4326e6c84d844e)
department表的主键字段deptid是employee表的字段。在上面的关系中,department表称为主表(master table),employee表称为子表(child table),deptid字段称为employee表的外键。
employee表的外键还可以简写成如下的形式,将主表的字段名去掉,此时外键中主表字段名默认是主表的主键。
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/61_3.jpg?sign=1739250815-iB8IkD62SVu934PqvNhFyXHoL1wWYwiT-0-558668fea9cc7f01982bea74253e8f71)
2.组合外键约束
外键约束也可以是多个字段的组合,以表约束的形式呈现。
主表如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/61_4.jpg?sign=1739250815-085Z4QgN641uh2H7AGUX63ewHtts8lyX-0-0bd59e53a4d121d293e300a4a658414a)
子表如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/61_5.jpg?sign=1739250815-31IB9zDj9PJqrVL8E2olHb2BtwInm1CS-0-7197ca9f79f6241c4721e6b46a0ef6da)
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/62_1.jpg?sign=1739250815-32eBiQi3n5KLeWQsFYxn1IQpyOR8TRgu-0-8f7fde5f9433300af1ba0f022a7717e8)
多字段外键的要求是主表的主键字段与子表的外键字段的个数和类型都必须一致。
3.多个外键约束
有时,有关联关系的表可能会存在多个,因此,一个表还可以有多个外键。例如,有一个优秀员工表excellent_employee,它包含两个外键,分别是department表中的deptid和employee表中的empid。
主表如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/62_2.jpg?sign=1739250815-k2jXCsfqCUOMcyRly3UJGKvpl5dmrpWP-0-149a71e7f838ba0dfcd0409b8531375d)
子表1如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/62_3.jpg?sign=1739250815-mwry3CIhE9w22tsJPOfBvdNJb7Z2Luty-0-55039fa74f45ab035ce7101002307689)
子表2如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/62_4.jpg?sign=1739250815-1Rwr8823vEBOubxUvhbCNkYUxljO9qpC-0-9f4d5675bc9970a0f4ea7679080ab533)
3.5.8 实例7:设置表的属性值自动增加
PostgreSQL有两种方法设置表的属性值使其自动增加。
第1种方法
首先创建一个序列,然后创建一个表,将表的字段默认值设置为该序列的NEXT值,代码如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/62_5.jpg?sign=1739250815-03R3P5PP9JiPg7Nr79ADogLgFFN4i6xK-0-c5e7225db24b61db47dcdb7636b194ee)
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/63_1.jpg?sign=1739250815-pxrvdKGJwppBNOLrwbzem3m5eO4GvEHZ-0-0220967b1e4045031c45ec72f40b449e)
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/63_2.jpg?sign=1739250815-YrGzuZHXBovgs8upVT97O1mTeStVYaOj-0-95a918c13016d054e4e009de6d36df58)
如果向tb_test表插入记录时字段a的值没有被指定,则seq_test表读取序列的下一个值作为字段a的值。
第2种方法
直接使用serial数据类型,效果等同于第1种方法,代码如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/63_3.jpg?sign=1739250815-PH0ckeDxLOpsWFbsYLc67q1JPq3BsIS2-0-1859fed610a17b3e77d7fe84cec3cf80)
3.5.9 实例8:查看表结构
查看表结构的方法在3.2.2节已经提到过,在psql命令行使用“\d表名”命令即可查询出表结构信息,代码如下:
![](https://epubservercos.yuewen.com/8D7397/16679181404813706/epubprivate/OEBPS/Images/63_4.jpg?sign=1739250815-OWSgxuPDzl3oQ9TcAGMwqrtntHDXPbJ0-0-03f4a4ad931c5bbded9dd53ee99e3cfc)
也可以通过查询系统表pg_class的方式获取表结构信息。