数据库完整性

类型

有四种数据库完整性约束的分类。

注:这部分参考https://blog.csdn.net/bzhxuexi/article/details/43671251

实体完整性

用来确保数据库中一个特定实体的记录唯一。

具体来说有以下约束方法:

约束方法 功能描述
primary key 主键约束 唯一识别数据库每一行的主键标志,可以包含多个列
identity 自增约束 指明一个列是由数据库自增序号生成,不能手动插入值
unique 唯一约束 确保列的值在每一行中都不同,没有重复值(null除外)

域完整性

域完整性是用来规定列的数据应该满足什么样的取值范围的,确保插入和修改的数据合理。

约束方法 功能描述
check 检查约束 用来限定列值的取值范围
foreign key 外键约束 指明列中的值是参考其他表的主键取值,而不能随意取值
default 默认值约束 如果没有指定值,插入时给改列赋值为默认值
not null 非空约束 强制指明该列不接受空值

参照完整性

又叫做“引用完整性”,指的是:如果一张表的主键作为另一张表的外键出现,那么外键的取值只能和主键保持一致,或者为null,而不能随意取其他值。

参照完整性约束实现的方式是通过外键约束来规定。

用户自定义完整性

特别应用情境下,用户可以根据需要自定义一些完整性规则。

完整性具体实现方式

可以在创建表的时候,为创建的语句加入列约束表约束,来实现数据库完整性的规定。

列约束是指,在申明列的时候就在后面顺带写上对这个列内值的约束。可以使用的约束方法包括:主键、外键、唯一、检查、默认、非空、自增。

表约束则是在声明了所有列后,单独增加的约束语句,此时必须要指定约束的列名。可以使用的约束方法包括:主键、外键、唯一、检查。

不管是写列约束还是表约束,都可以选择性加一个constraint <约束名>来指定一个约束的名字,这样方便创建之后对约束内容进行更改。

下面来说一下实现各种约束方法具体的SQL语句该怎么写。

主键约束

如果以列约束的方式去写,只需要在列声明后面写[constraint <约束名>] primary key 就可以指定一个列为主键列。(方括号表示可选)

如果是写成表约束,则可以指定多个列为主键。写法为 [constraint <约束名>] primary key(col1, col2 ...)

唯一约束

和主键约束一样的,改成unique就行了。一个表中可以有多个唯一约束,但只能有一个主键约束。

外键约束

列约束的方式可以写成[constraint <约束名>] REFERENCES <父表名>[(<属性名>)],而表约束中要多指明列名:[constraint <约束名>] foreign key (<列名>) REFERENCES <父表名>[(<属性名>)]。注意参考表的属性名是可选的,一般要参考主键列。

另外,SQL还对违反参照完整性约束的行为制定了三种策略:

  • restrict,严格。如果有违反完整性的行为就拒绝。默认是这种。
  • cascade,级联。如果有违反的行为影响了被参照表的主键,就把这种影响扩散到参照它的表中。比如删除了被参照表中的一个行,就会级联地删除参照它的表中对应外键的行。
  • set null,置空。把被参照表中的一个行删除后,参照它的表中相同的外键被设置为null

可以通过on delete或者on update来指定触发处理策略的行为。比如on delete cascade表示删除是使用级联策略。

直接在外键约束后面加上策略方式就可以应用。比如foreign key (cid) on delete set null

检查约束

[constraint <约束名>] check(<检查条件表达式>)即可,不满足表达式(表达式计算结果为false)的插入和修改行为将被拒绝。如果以表约束来写,可以涉及多个列。

默认约束

只能写在列后面,表示这个列的默认值(缺省值)。

[constraint <约束名>] default <值>

非空约束

在列后面写上not null即可

自增约束

在列后面写上identity(<起始值>,<增量>)。如果不写起始值和增量,默认都是1,也就是表中每增加一个行,自动给该行的这个列分配一个上次+1的值。

修改表

可以使用alter table语句来改变列和约束。

列的操作:

  • add 添加
  • drop 删除
  • modify 更改

约束的操作:

  • add 添加
  • drop 删除

数据库触发器

CREATE TRIGGER trigger_name {BEFORE|AFTER}
{INSERT|DELETE|UPDATE [OF col1, col2...]}
ON table_name
[FOR EACH ROW|FOR EACH STATEMENT]
[WHEN (searching condition)]
BEGIN
{...statement...}
END

第一行的before和after指定触发的时机实在事件发生之前还是之后,第二行是触发条件,第三行是指定作用在哪个表,第四行可以选择指定粒度(每个被牵连的行触发一次还是一个sql语句触发一次),第五行可以指定额外的条件,然后begin和end中间指定要做的事。

SELECT name FROM sqlite_master WHERE type = 'trigger';可以列出数据库所有触发器。而DROP TRIGGER trigger_name;语句用来删除触发器。

视图

视图就是将查询的结果集可视化的表,所以和表有着很多重合的用法。

视图是虚拟的,也就是说如果依赖的表发生变化,则视图也会变;如果对可更新视图进行修改,则表内容也会被修改。

创建、查看和删除

使用create view <view_name> as <查询语句>的方法就可以根据查询结果创建一个视图,也可以在as前面加上一些列名,给视图的列重命名。当查询中涉及到重名的列时,则必须给列重命名,否则会创建失败。

在查询语句的后面加上with check option 可以给视图绑定上和查询中where后面一样的检查条件,这样就禁止了向视图中插入非法的行的行为。

select view_name from user_views;可以像表一样查询视图。

可以使用describe {view_name|table_name}来查看视图状态。

drop view view_name可以删除视图。如果后面加上cascade则表示级联删除,就是说如果这个视图上嵌套有其他视图,则一并删除。如果加上restrict(默认情况),就不允许删除还存在嵌套视图的视图。

可更新视图和只读视图

如果一个视图内容来自多个表,则一定是只读的。如果在创建时视图的时候用了group by语句,则也只读。

更新视图实际上是在间接更新表中的数据,所以有时候有些列允许通过视图更新,有些不允许。可以通过select column_name, updatable from user_updatable_columns where table_name ="AGENTORDERS"展示可更新的列。

安全性和权限

通过grant语句来给用户赋予权限:

grant <权限名...>
on [table] table_name | view_name
to <用户名...>
[with grant option]

如果加上最后一句with grant option则表示得到权限的用户也可以把自己拥有的权限再赋予其他人。

常用的权限有select、delete、insert、update(后面可以写列名)、references等。update后面指定列名表示仅允许对一些列进行修改。

通过revoke语句来撤销权限。