一、字段修饰符(约束)
1、null和not null修饰符
举例来说明两个修饰符的区别
mysql> create database xuegod2;
Query OK, 1 row affected (0.00 sec)
mysql> use xuegod2;
Database changed
mysql> create table worker(id int not null,name varchar(8) not null,pass varchar(20) not null);
Query OK, 0 rows affected (0.03 sec)
mysql> desc worker;
±------±------------±-----±----±--------±------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±------+
| id | int(11) | NO | | NULL | |
| name | varchar(8) | NO | | NULL | |
| pass | varchar(20) | NO | | NULL | |
±------±------------±-----±----±--------±------+
3 rows in set (0.07 sec)
mysql> insert into worker values (1,‘HA’,123456);
Query OK, 1 row affected (0.00 sec)
mysql> insert into worker values (1,‘HA’,’’); #可以插入空值
Query OK, 1 row affected (0.00 sec)
mysql> insert into worker values (1,‘HA’,null); #不能插入null
ERROR 1048 (23000): Column ‘pass’ cannot be null
总结:not null的字段只能插入空值,不能插入null
2、我们可能有这些疑问
(1)字段类型是not null,为什么可以插入空值
(2)为什么not null的效率比null高
(3)判断字段不为空的时候,到底要 select * from table where column <> ‘’ 还是要用 select * from table where column is not null 呢。
3、“空值” 和 “NULL”有什么不一样?
(1)空值是不占用空间的
(2)MySQL中的NULL其实是占用空间的,下面是来自于MySQL官方的解释
“NULL columns require additional space in the row to record whether their values are NULL. For MyISAM tables, each NULL column takes one bit extra, rounded up to the nearest byte.”
#“空列需要行中的额外空间来记录其值是否为空。对于MyISAM表,每个NULL列需要一个额外的位,四舍五入到最接近的字节。
比如:一个杯子,空值’'代表杯子是真空的,NULL代表杯子中装满了空气,虽然杯子看起来都是空的,但是里面是有空气的。
4、对于问题2,为什么not null的效率比null高?
NULL 其实并不是空值,而是要占用空间,所以mysql在进行比较的时候,NULL 会参与字段比较,所以对效率有一部分影响。
而且索引时不会存储NULL值的,所以如果索引的字段可以为NULL,索引的效率会下降很多。
-MySQL难以优化引用可空列查询,它会使索引、索引统计和值更加复杂。可空列需要更多的存储空间,还需要MySQL内部进行特殊处理。可空列被索引后,每条记录都需要一个额外的字节,还能导致MyISAM中固定大小的索引变成可变大小的索引--------这也是《高性能MySQL第二版》介绍的解读:“可空列需要更多的存储空间”:需要一个额外字节作为判断是否为NULL的标志位“需要MySQL内部进行特殊处理”
所以使用not null 比null效率高
总结:因为null会占用空间,索引的时候需要查找对比,所以没有not null效率高
5、对于问题3,判断字段不为空的时候,到底要 select * from table where column <> ‘’ 还是要用 select * from table where column is not null我们举例看看
mysql> create table test(col1 varchar(10) not null,col2 varchar(10) null)ENGINE=MyISAM;
Query OK, 0 rows affected (0.00 sec)
mysql> desc test;
±------±------------±-----±----±--------±------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±------+
| col1 | varchar(10) | NO | | NULL | |
| col2 | varchar(10) | YES | | NULL | |
±------±------------±-----±----±--------±------+
2 rows in set (0.00 sec)
mysql> insert into test values ("",null);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test values (“1”,“2”);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test values ("",“1”);
Query OK, 1 row affected (0.00 sec)
mysql> insert into test values (null,""); #col1不能为null
ERROR 1048 (23000): Column ‘col1’ cannot be null
mysql> select * from test;
±-----±-----+
| col1 | col2 |
±-----±-----+
| | NULL |
| 1 | 2 |
| | 1 |
±-----±-----+
4 rows in set (0.00 sec)
mysql> select * from test where col1 is not null;
±-----±-----+
| col1 | col2 |
±-----±-----+
| | NULL |
| | |
| 1 | 2 |
| | 1 |
±-----±-----+
4 rows in set (0.00 sec)
mysql> select * from test where col1 <> “”;
±-----±-----+
| col1 | col2 |
±-----±-----+
| 1 | 2 |
±-----±-----+
1 row in set (0.00 sec)
mysql> select * from test where col1 != “”;
±-----±-----+
| col1 | col2 |
±-----±-----+
| 1 | 2 |
±-----±-----+
1 row in set (0.00 sec)
6、default设定字段的默认值
mysql> create table test2(name varchar(8) not null,dept varchar(25) default ‘SOS’);
Query OK, 0 rows affected (0.04 sec)
mysql> desc test2;
±------±------------±-----±----±--------±------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±------+
| name | varchar(8) | NO | | NULL | |
| dept | varchar(25) | YES | | SOS | |
±------±------------±-----±----±--------±------+
2 rows in set (0.01 sec)
mysql> insert into test2(name) values (‘kko’); #直插入name字段,dept不写
Query OK, 1 row affected (0.00 sec)
mysql> select * from test2;
±-----±-----+
| name | dept |
±-----±-----+
| kko | SOS | #可以看到这个字段默认将SOS插入到表中
±-----±-----+
1 row in set (0.00 sec)
总结:
如果字段没有设定default ,MySQL依据这个字段是null还是not null,如果为可以为null,则为null。如果不可以为null,则报错。
如果时间字段,默认为当前时间 ,插入0时,默认为当前时间。
如果是enum 类型,默认为第一个元素。
7、auto_increment字段约束
自动增长
只能修饰 int字段。 表明MySQL应该自动为该字段生成一个唯一没有用过的数(每次在最大ID值的基础上加1。特例:如果目前最大ID是34,然后删除34,新添加的会是35.)。对于主键,这是非常 有用的。可以为每条记录创建一个惟一的标识符
mysql> create table items(id int not null auto_increment primary key,label varchar(20) not null);
Query OK, 0 rows affected (0.05 sec)
mysql> desc items;
±------±------------±-----±----±--------±---------------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±---------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| label | varchar(20) | NO | | NULL | |
±------±------------±-----±----±--------±---------------+
2 rows in set (0.00 sec)
mysql> insert into items(label) values (‘aaba’);
Query OK, 1 row affected (0.00 sec)
mysql> insert into items values (9,‘aaba’);
Query OK, 1 row affected (0.00 sec)
mysql> insert into items(label) values (‘abc’);
Query OK, 1 row affected (0.01 sec)
mysql> select * from items;
±—±------+
| id | label |
±—±------+
| 1 | aaba | #默认从1开始自增长
| 9 | aaba | #手动指定id为9后,下次增长从9开始加1
| 10 | abc | #9开始加1,所以是10
±—±------+
3 rows in set (0.00 sec)
mysql> insert into items values (9,‘adf’);
ERROR 1062 (23000): Duplicate entry ‘9’ for key ‘PRIMARY’
#id为9的已经存在,主键有唯一性
mysql> insert into items(label) values (‘ccc’);
Query OK, 1 row affected (0.00 sec)
mysql> select * from items; #插入一行数据后,id值为11
±—±------+
| id | label |
±—±------+
| 1 | aaba |
| 9 | aaba |
| 10 | abc |
| 11 | ccc |
±—±------+
4 rows in set (0.00 sec)
mysql> delete from items where id=11;
Query OK, 1 row affected (0.01 sec)
mysql> select * from items; #删除一行后,id=11的行没有了
±—±------+
| id | label |
±—±------+
| 1 | aaba |
| 9 | aaba |
| 10 | abc |
±—±------+
3 rows in set (0.00 sec)
mysql> insert into items(label) values (‘bbb’);
Query OK, 1 row affected (0.00 sec)
mysql> select * from items; #再次插入一行,发现id是从12开始,
±—±------+
| id | label |
±—±------+
| 1 | aaba |
| 9 | aaba |
| 10 | abc |
| 12 | bbb |
±—±------+
4 rows in set (0.00 sec)
总结:虽然删除了id=11的行,但是主键还是会按照刚刚最大的id进行自增长
8、清楚表中的记录
1)方法1,使用delete清空数据
delete 不加where条件,清空所有表记录。但是delete不会清零auto_increment 值
mysql> delete from items;
Query OK, 4 rows affected (0.01 sec)
mysql> select * from items;
Empty set (0.00 sec)
mysql> insert into items(label) values (‘lsdj’);
Query OK, 1 row affected (0.01 sec)
mysql> select * from items; #这里可以看到虽然清空了,但是ID还是按照之情最大的进行增长
±—±------+
| id | label |
±—±------+
| 13 | lsdj |
±—±------+
1 row in set (0.00 sec)
2)方法2,使用truncate,删除表中的记录
作用: 删除表的所有记录,并清零auto_increment 值。新插入的记录从1开始。
语法: truncate table name;
mysql> truncate table items;
Query OK, 0 rows affected (0.01 sec)
mysql> select * from items;
Empty set (0.00 sec)
mysql> insert into items(label) values (‘sdfd’);
Query OK, 1 row affected (0.00 sec)
mysql> select * from items; #id值从1开始增长
±—±------+
| id | label |
±—±------+
| 1 | sdfd |
±—±------+
1 row in set (0.00 sec)
二、索引
索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。更通俗的说,数据库索引好比是一本书前面的目录,能加快数据库的查询速度。
优点:为了加快搜索速度,减少查询时间。
缺点:
索引是以文件存储的。如果索引过多,占磁盘空间较大。而且他影响: insert ,update ,delete 执行时间。
索引中数据必须与数据表数据同步:如果索引过多,当表中数据更新的时候后,索引也要同步更新,这就降低了效率。
索引的类型:
1)普通索引
2)唯一性索引
3)主键索引(主索引)
4) 复合索引
1、普通索引
最基本的索引,不具备唯一性,就是加快查询速度
1)创建表是直接创建索引
语法:create table 表名 (列定义 index 索引名称(字段) index 索引名称(字段));
注:可以使用key,也可以使用index 。index 索引名称 (字段) ,索引名称,可以加也可以不加,不加使用字段名作为索引名。
mysql> create table demo(id int(4),name varchar(20),pwd varchar(20),index(pwd));
Query OK, 0 rows affected (0.01 sec)
mysql> desc demo;
±------±------------±-----±----±--------±------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±------+
| id | int(4) | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| pwd | varchar(20) | YES | MUL | NULL | | #MUL表示普通索引
±------±------------±-----±----±--------±------+
3 rows in set (0.00 sec)
mysql> create table demo1(id int(4),name varchar(20),pwd varchar(20),key(pwd));
#使用key创建普通索引
Query OK, 0 rows affected (0.04 sec)
mysql> desc demo1;
±------±------------±-----±----±--------±------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±------+
| id | int(4) | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| pwd | varchar(20) | YES | MUL | NULL | |
±------±------------±-----±----±--------±------+
3 rows in set (0.00 sec)
mysql> create table demo2(id int(4),name varchar(20),pwd varchar(20),key key_pwd(pwd));
#创建普通索引是key前面加上所以的名称,不加默认使用字段的名称作为索引的名称
Query OK, 0 rows affected (0.01 sec)
mysql> desc demo2;
±------±------------±-----±----±--------±------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±------+
| id | int(4) | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| pwd | varchar(20) | YES | MUL | NULL | |
±------±------------±-----±----±--------±------+
3 rows in set (0.00 sec)
mysql> show create table demo2; #可以看到数据库后台创建表的时候使用key_pwd作为名称
±------±-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
±------±-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| demo2 | CREATE TABLE demo2
(
id
int(4) DEFAULT NULL,
name
varchar(20) DEFAULT NULL,
pwd
varchar(20) DEFAULT NULL,
KEY key_pwd
(pwd
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
±------±-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
2)当表创建完成后,使用alter为表添加索引
语法:alter table 表名 add index 索引名 (字段1,字段2);
注:如果Key是MUL, 就是一般性索引,该列的值可以重复, 该列是一个非唯一索引的前导列(第一列)或者是一个唯一性索引的组成部分但是可以含有空值NULL。就是表示是一个普通索引。
先删除demo的普通索引
mysql> alter table demo drop index pwd;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc demo;
±------±------------±-----±----±--------±------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±------+
| id | int(4) | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| pwd | varchar(20) | YES | | NULL | | #key值已经没有MUL了
±------±------------±-----±----±--------±------+
3 rows in set (0.00 sec)
手动添加普通索引
mysql> alter table demo add key key_pwd(pwd);
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc demo;
±------±------------±-----±----±--------±------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±------+
| id | int(4) | YES | | NULL | |
| name | varchar(20) | YES | | NULL | |
| pwd | varchar(20) | YES | MUL | NULL | |
±------±------------±-----±----±--------±------+
3 rows in set (0.00 sec)
2、唯一索引
与普通索引基本相同,但有一个区别:索引列的所有值都只能出现一次,即必须唯一,用来约束内容,字段值只能出现一次,应该加唯一索引。唯一性允许有NULL值<允许为空>。
1)创建表是,添加唯一索引
语法:create table 表名 (列定义 unique key 索引名(字段));
mysql> create table demo3 (id int(10) not null auto_increment primary key,name varchar(20) not null,pass varchar(20),unique index pass_unique(pass));
Query OK, 0 rows affected (0.02 sec)
mysql> desc demo3;
±------±------------±-----±----±--------±---------------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±---------------+
| id | int(10) | NO | PRI | NULL | auto_increment | #主键索引 ,自增长
| name | varchar(20) | NO | | NULL | |
| pass | varchar(20) | YES | UNI | NULL | | #唯一索引,UNI
±------±------------±-----±----±--------±---------------+
3 rows in set (0.00 sec)
2)已经创建的表,使用alter添加唯一索引
语法:alter table 表名 add unique index 索引名 (字段);
mysql> alter table demo3 drop key pass_unique; #key后加上唯一索引的名称
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table demo3 add unique index (pass); #使用key (pass)也可以
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc demo3;
±------±------------±-----±----±--------±---------------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±---------------+
| id | int(10) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
| pass | varchar(20) | YES | UNI | NULL | | #添加索引成功
±------±------------±-----±----±--------±---------------+
3 rows in set (0.00 sec)
3.主键索引
查询数据库,按主键查询是最快的,每个表只能有一个主键列,可以有多个普通索引列。主键列要求列的所有内容必须唯一,而索引列不要求内容必须唯一,不允许为空
1)创建表时,创建组件索引
语法:create table 表名 (列定义 primary index 索引名(字段名));
mysql> create table demo4 (id int(8) not null auto_increment primary key,name varchar(20) not null,pass varchar(20) not null,index (name),unique index (pass));
#id列为主键索引,自增长,内容唯一,不能为空;
name列为普通索引,不允许为null;
pass列为唯一索引,不允许为;
Query OK, 0 rows affected (0.01 sec)
mysql> desc demo4;
±------±------------±-----±----±--------±---------------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±---------------+
| id | int(8) | NO | PRI | NULL | auto_increment | #不能为空,主键索引,自增长
| name | varchar(20) | NO | MUL | NULL | | #不允许为null,普通索引
| pass | varchar(20) | NO | UNI | NULL | | #默认不允许为null,唯一索引
±------±------------±-----±----±--------±---------------+
3 rows in set (0.02 sec)
2)创建表后添加主键索引
不推荐,因为表内列的数据,不确定是否唯一,创建主键索引会报错
mysql> alter table demo4 drop primary key; #删除主键索引报错,因为自增张索引的原因
ERROR 1075 (42000): Incorrect table definition; there can be only one auto column and it must bedefined as a key
mysql> alter table demo4 change id id int(8) not null; #直接not null取消自增张
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc demo4;
±------±------------±-----±----±--------±------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±------+
| id | int(8) | NO | PRI | NULL | |
| name | varchar(20) | NO | MUL | NULL | |
| pass | varchar(20) | NO | UNI | NULL | |
±------±------------±-----±----±--------±------+
3 rows in set (0.00 sec)
mysql> alter table demo4 drop primary key; #删除主键索引
Query OK, 0 rows affected (0.06 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc demo4;
±------±------------±-----±----±--------±------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±------+
| id | int(8) | NO | | NULL | |
| name | varchar(20) | NO | MUL | NULL | |
| pass | varchar(20) | NO | PRI | NULL | |
±------±------------±-----±----±--------±------+
3 rows in set (0.00 sec)
mysql> alter table demo4 change id id int(8) not null primary key auto_increment;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> desc demo4;
±------±------------±-----±----±--------±---------------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±---------------+
| id | int(8) | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | MUL | NULL | |
| pass | varchar(20) | NO | UNI | NULL | |
±------±------------±-----±----±--------±---------------+
3 rows in set (0.00 sec)
5、复合索引
索引可以包含一个、两个或更多个列。两个或更多个列上的索引被称作复合索引
例: 创建一个表存放服务器允许或拒绝的IP和port,要记录中IP和port要唯一
mysql> create table firewall(host varchar(15) not null,prot smallint(4) not null,access enum(‘deny’,‘allow’) not null,primary key (host,prot));
Query OK, 0 rows affected (0.01 sec)
mysql> desc firewall;
±-------±---------------------±-----±----±--------±------+
| Field | Type | Null | Key | Default | Extra |
±-------±---------------------±-----±----±--------±------+
| host | varchar(15) | NO | PRI | NULL | |
| prot | smallint(4) | NO | PRI | NULL | |
| access | enum(‘deny’,‘allow’) | NO | | NULL | |
±-------±---------------------±-----±----±--------±------+
3 rows in set (0.00 sec)
mysql> insert into firewall values (‘10.1.1.1’,22,‘deny’);
Query OK, 1 row affected (0.00 sec)
mysql> insert into firewall values (‘10.1.1.1’,21,‘deny’);
Query OK, 1 row affected (0.00 sec)
mysql> insert into firewall values (‘10.1.1.1’,21,‘deny’); #host和prot列有重复,不唯一
ERROR 1062 (23000): Duplicate entry ‘10.1.1.1-21’ for key ‘PRIMARY’
总结:建表的时候如果加各种索引,顺序如下:
create table 表名(字段定义,primary key (字段名),unique index (字段名),index (字段名))
主键索引(复合索引)—>唯一索引—>普通索引
6、全文索引
全文索引(也称全文检索)是目前搜索引擎使用的一种关键技术。它能够利用「分词技术「等多种算法智能分析出文本文字中关键字词的频率及重要性,然后按照一定的算法规则智能地筛选出我们想要的搜索结果。
MySQL在数据量较大的情况下,高并发连接的情况下。
select 语句 where bName like ‘%网%’
使用% _ 通配符,不通过索引,直接全表扫描。
ABSUWU LIKE ‘%U_U’
数据库压力大。
MySQL的解决方案:全文索引:3.2开始支持全文索引。无法正确支持中文。
从MySQL 5.7.6开始 MySQL内置了ngram全文检索插件,用来支持中文分词
查看表当前默认的存储引擎:
语法:show create table 表名;
全文索引只能用在 varchar text
1)创建表时创建全文索引
语法:create table 表名 (字段定义列 fulltext key 索引名 (字段));
2)修改表示添加全文索引
语法:alter talbe 表名 add fulltext key 索引名 (字段);
强烈注意:MySQL自带的全文索引只能用于数据库引擎为MyISAM的数据表,如果是其他数据引擎,则全文索引不会生效。
一般交给第三方软件进行全文索引。
http://sphinxsearch.com/
7、索引设计的原则
1)索引并非越多越好
2)数据量不大的不需要建立索引
3)列中的值变化不多不需要建立索引 row id
4)经常排序(order by 字段)和分组(group by 字段)的列需要建立索引
select a.bTypeId,(select b.bTypeName from category b where a.bTypeId = b.bTypeId) bn,count(*) from books a group by bTypeId;
5)唯一性约束对应使用唯一性索引
table (id pri,use,name index,pass);
三、外键约束
1、什么是外键约束
foreign key就是表与表之间的某种约定的关系,由于这种关系的存在,我们能够让表与表之间的数据,更加的完整,关联性更强。
关于完整性,关联性我们举个例子
例:
有二张表,一张是用户表,一张是订单表
1)如果我删除了用户表里的用户,那么订单表里面与这个用户有关的数据,就成了无头数据了,不完整了。
2)如果我在订单表里面,随便插入了一条数据,这个订单在用户表里面,没有与之对应的用户。这样数据也不完整了。
如果有外键的话,就方便多了,可以不让用户删除数据,或者删除用户的话,通过外键同样删除订单表里面的数据,这样也能让数据完整。
2、创建外键约束
1)使用create talbe 创建外键
语法:create table 表名 (字段定义列 [CONSTRAINT [约束名称]] FOREIGN KEY [外键字段]
REFERENCES 外键表名
[ON DELETE CASCADE ]
[ON UPDATE CASCADE ])
关于参数的解释:
RESTRICT: 拒绝对父表的删除或更新操作。
CASCADE: 从父表删除或更新且自动删除或更新子表中匹配的行。ON DELETE CASCADE和ON UPDATE CASCADE都可用
注意:on update cascade是级联更新的意思,on delete cascade是级联删除的意思,意思就是说当你更新或删除主键表,那外键表也会跟随一起更新或删除。
精简后的语法:
foreign key 当前表的字段 references 外部表名 (关联的字段) ENGINE =innodb
注意创建成功,必须满足4个条件
确保参照的表和字段存在。
组成外键的字段被索引。
必须使用ENGINE指定存储引擎为:innodb。
外键字段和关联字段,数据类型必须一致。
mysql> create table user
(id int(11) not null auto_increment,name varchar(50) not null default “”,sex int(1) not null default “0”,primary key (id))ENGINE=innodb;
Query OK, 0 rows affected (0.01 sec)
mysql> desc user
;
±------±------------±-----±----±--------±---------------+
| Field | Type | Null | Key | Default | Extra |
±------±------------±-----±----±--------±---------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(50) | NO | | | |
| sex | int(1) | NO | | 0 | |
±------±------------±-----±----±--------±---------------+
3 rows in set (0.00 sec)
mysql> create table order
(o_id int(11) auto_increment,u_id int(11) default ‘0’,username varchar(50),money int(11),primary key (o_id),index (u_id),foreign key order_f_key(u_id) references user(id) on delete cascade on update cascade)ENGINE=innodb;
Query OK, 0 rows affected (0.02 sec)
mysql> desc order
;
±---------±------------±-----±----±--------±---------------+
| Field | Type | Null | Key | Default | Extra |
±---------±------------±-----±----±--------±---------------+
| o_id | int(11) | NO | PRI | NULL | auto_increment |
| u_id | int(11) | YES | MUL | 0 | |
| username | varchar(50) | YES | | NULL | |
| money | int(11) | YES | | NULL | |
±---------±------------±-----±----±--------±---------------+
4 rows in set (0.00 sec)
注:
on delete cascade on update cascade 添加级联删除和更新。
确保参照的表user中id字段存在。 组成外键的字段u_id被索引。 必须使用type指定存储引擎为:innodb。
外键字段和关联字段,数据类型必须一致。
插入测试数据
mysql> insert into user(name,sex) values (‘HA’,1),(‘LB’,2),(‘HPC’,3);
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql>insert into order
(u_id,username,money)values(1,‘HA’,234),(2,‘LB’,146),(3,‘HPC’,256);
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from order
;
±-----±-----±---------±------+
| o_id | u_id | username | money |
±-----±-----±---------±------+
| 1 | 1 | HA | 234 |
| 2 | 2 | LB | 146 |
| 3 | 3 | HPC | 256 |
±-----±-----±---------±------+
3 rows in set (0.00 sec)
多表结合查询:因为没有重复的列,所以不用别名
mysql> select id,name,sex,money,o_id from user,order
where id=u_id;
±—±-----±----±------±-----+
| id | name | sex | money | o_id |
±—±-----±----±------±-----+
| 1 | HA | 1 | 234 | 1 |
| 2 | LB | 2 | 146 | 2 |
| 3 | HPC | 3 | 256 | 3 |
±—±-----±----±------±-----+
3 rows in set (0.00 sec)
测试外键删除约束
mysql> delete from user where id=1; #删除user表id为1的列,order表也对应删除
Query OK, 1 row affected (0.01 sec)
mysql> select id,name,sex,money,o_id from user,order
where id=u_id;
±—±-----±----±------±-----+
| id | name | sex | money | o_id |
±—±-----±----±------±-----+
| 2 | LB | 2 | 146 | 2 |
| 3 | HPC | 3 | 256 | 3 |
±—±-----±----±------±-----+
2 rows in set (0.00 sec)
测试外键更新约束
mysql> update user set id=6 where id=2; #将user表id为2该成6,看order表是否会更改
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select id,name,sex,money,o_id from user,order
where id=u_id;
±—±-----±----±------±-----+
| id | name | sex | money | o_id |
±—±-----±----±------±-----+
| 3 | HPC | 3 | 256 | 3 |
| 6 | LB | 2 | 146 | 2 |
±—±-----±----±------±-----+
2 rows in set (0.00 sec)
测试外键约束,给order表增加一个user没有的u_id值
mysql> insert into order
values (5,5,‘Find’,100);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (xuegod2
.order
, CONSTRAINT order_ibfk_1
FOREIGN KEY (u_id
) REFERENCES user
(id
) ON DELETE CASCADE ON UPDATE CASCADE)
先给user表插入一个id=5的数据
mysql> insert into user
values (5,‘Find’,1);
Query OK, 1 row affected (0.00 sec)
mysql> insert into order
values (5,5,‘Find’,100); #可以插入成功
Query OK, 1 row affected (0.00 sec)
mysql> select * from order
;
±-----±-----±---------±------+
| o_id | u_id | username | money |
±-----±-----±---------±------+
| 2 | 6 | LB | 146 |
| 3 | 3 | HPC | 256 |
| 5 | 5 | Find | 100 |
±-----±-----±---------±------+
3 rows in set (0.00 sec)
mysql> select * from user
;
±—±-----±----+
| id | name | sex |
±—±-----±----+
| 3 | HPC | 3 |
| 5 | Find | 1 |
| 6 | LB | 2 |
±—±-----±----+
3 rows in set (0.00 sec)
2)通过alter table 创建外键和级联更新,级联删除
语法:
alter table 数据表名称 add
[constraint [约束名称] ] foreign key (外键字段,…) references 数据表(参照字段,…)
[on update cascade|set null|no action]
[on delete cascade|set null|no action]
)
mysql> create table order1(o_id int(11) auto_increment, u_id int(11) default ‘0’, username varchar(50), money int(11), primary key(o_id), index(u_id)) ENGINE=innodb;
Query OK, 0 rows affected (0.02 sec)
mysql> alter table order1 add foreign key(u_id) references user(id) on delete cascade on update cascade, ENGINE =innodb;
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> alter table order1 add constraint bk
foreign key(u_id) references user(id) on delete cascade on update cascade,ENGINE=InnoDB; ##指定外键名称
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
3)删除外键
语法:alter table 数据表名称 drop foreign key 约束(外键)名称
mysql> alter table order1 drop foreign key bk; #bk是外键名称
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show create table order1;
±-------±----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
±-------±----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| order1 | CREATE TABLE order1
(
o_id
int(11) NOT NULL AUTO_INCREMENT,
u_id
int(11) DEFAULT ‘0’,
username
varchar(50) DEFAULT NULL,
money
int(11) DEFAULT NULL,
PRIMARY KEY (o_id
),
KEY u_id
(u_id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
±-------±----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
四、视图
视图就是一个存在于数据库中的虚拟表。
视图本身没有数据,只是通过执行相应的select语句完成获得相应的数据。
我们在怎样的场景使用它,为什么使用视图 :
如果某个查询结果出现的非常频繁,也就是,要经常拿这个查询结果来做子查询这种
1)视图能够简化用户的操作
视图机制用户可以将注意力集中在所关心的数据上。如果这些数据不是直接来自基本表,则可以通过定义视图,使数据库看起来结构简单、清晰,并且可以简化用户的数据查询操作
2)视图是用户能以不同的角度看待同样的数据。
对于固定的一些基本表,我们可以给不同的用户建立不同的视图,这样不同的用户就可以看到自己需要的信息了。
3)视图对重构数据库提供了一定程度的逻辑性。
比如原来的A表被分割成了B表和C表,我们仍然可以在B表和C表的基础上构建一个视图A,而使用该数据表的程序可以不变。
4)视图能够对机密数据提供安全保护
比如说,每门课的成绩都构成了一个基本表,但是对于每个同学只可以查看自己这门课的成绩,因此可以为每个同学建立一个视图,隐藏其他同学的数据,只显示该同学自己的
5)适当的利用视图可以更加清晰的表达查询数据。
有时用现有的视图进行查询可以极大的减小查询语句的复杂程度。
1、创建视图
语法:create view视图名称(即虚拟的表名) as select 语句。
1)在book数据库创建视图
mysql>use book;
mysql> create view bc as select b.bName ,b.price ,c.bTypeName from books as b left join category as c on b.bTypeId=c.bTypeId ;
可以按照普通表去访问。另外视图表中的数据和原数据表中数据是同步的。
2)查看视图创建信息
mysql> show create view bc \G
3)查询视图中的数据
mysql> select * from bc where price<40\G
2、更新或修改视图
语法:
alter view视图名称(即虚拟的表名) as select 语句。
update view视图名称(即虚拟的表名)set
mysql> alter view bc as select b.bName ,b.publishing ,c.bTypeId from books as b left join category as c on b.bTypeId=c.bTypeId;
mysql> select * from bc\G
3、删除视图
drop view 视图名。
mysql> drop view bc;
学习mysql 先搞懂它的概念原理,慢慢做实验理解它真正的用法,然后结合实际为什么要用这个SQL写法。