MySQL数据库

第四章 数据的完整性

作用:保证用户输入的数据保存到数据库中是正确的。

确保数据的完整性=在创建表时给表中添加约束。

完整性的分类:

  • 实体完整性;
  • 域完整性;
  • 引用完整性;

4.1 实体完整性

实体:即表中的一行(一条记录)代表一个实体(entity)。

实体完整性的作用:标识每一行数据不重复。

约束类型:

主键约束(primary key)

唯一约束(unique)

自动增长列(auto_increment)

4.1.1 主键约束(primary key)

注:每个表中要有一个主键

特点:数据唯一,且不能为null

示例:

第一种添加方式:

CREATE TABLE studdent(
    id int primary key,
    name varchar(50)
);

第二种添加方式:此种方式优势在于可以创建联合主键

CREATE TABLE student(
    id int,
    name varchar(50),
    primary key(id)
);
CREATE TABLE student(
    classid int,
    stuid int,
    name varchar(50),
    primary key(classid,stuid)
);

第三种添加方式:先创建表,然后再添加主键

CREATE TABLE studdent(
    id int;
    name varchar(50)
);
ALTER TABLE student ADD PRIMARY KEY(id);
4.1.2 唯一约束(unique)

特点:数据不能重复,可以为null

CREATE TABLE student(
    id int primary key,
    name varchar(50) unique
);
4.1.3 自动增长列(auto_increment)

sqlserver数据库(identity)oracle数据库(sequence)

给主键添加自动增长的数值,列只能是整数类型

CREATE TABLE student(
    id int primary key auto_increment,
    name varchar(50)
);

INSERT INTO student(name) values('tom');

修改自动增长的初始值:

ALTER TABLE tbl_name AUTO_INCREMENT = n;

4.2 域完整性

域完整性的作用:限制此单元格的数据正确,不对照此列的其他单元格比较

域代表当前单元格

域完整性约束:数据类型 非空约束(not null) 默认值约束(default)

check约束(MySQL不支持)check(sex='男' or sex='女')

4.2.1 数据类型

数值类型

类型

大小

范围(有符号)

范围(无符号)

用途

TINYINT

1字节

(-128,127)

(0,255)

小整数值

SMALLINT

2字节

(-32768,32767)

(0,65535)

大整数值

MEDIUMINT

3字节

(-8388608,8388607)

(0,16777215)

大整数值

INT或INTEGER

4字节

(-2147483648,2147483647)

(0,4294967295)

大整数值

BIGINT

8字节

(-9233372036854775808,9233372036854775807)

(0,18446744073709551615)

极大整数值

FLOAT

4字节

单精度浮点数值

DOUBLE

8字节

双精度浮点数值

DOUBLE(M,D)

8字节,M表示长度,D表示小数位数

同上,受M和D的约束

同上,受M和D的约束

双精度浮点数

DECIMAL(M,D)

DECIMAL(M,D),如果M>D,为M+2否则为D+2

依赖于M和D的值,M最大值为65

依赖于M和D的值,M最大值为65

小数值

日期类型:

表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。

每个时间类型有一个有效值范围和一个“零”值,当指定不合法的MySQL不能表示的值时使用“零”值。

类型

大小(字节)

范围

格式

用途

DATE

3

1000-01-01/9999-12-31

YYYY-MM-DD

日期值

TIME

3

‘-838:59:59’/‘838:59:59’

HH:MM;SS

时间值或持续时间

YEAR

1

1901/2155

YYYY

年份值

DATETIME

8

1000-01-01 00:00:00/9999-12-31 23:59:59

YYYY-MM-DD HH:MM:SS

混合日期和时间值

TIMESTAMP

4

1970-01-01 00:00:00/2038结束时间是第2147483647秒,北京时间2038-01-19 11:14:07,格林尼治时间2038年1月19日 凌晨03:14:07

YYYYMMDDHHMMSS

混合日期和时间值,时间戳

字符串类型:

类型

大小

用途

CHAR

0-255字符

定长字符串

VARCHAR

0-65536字节

变长字符串

TINYBLOB

0-255字节

不超过255个字符的二进制字符串

TINYTEXT

0-255字节

短文本字符串

BLOB

0-65536字节

二进制形式的长文本数据

TEXT

0-65536字节

长文本数据

MEDIUMBLOB

0-16777215字节

二进制形式的中等长度文本数据

MEDIUMTEXT

0-16777215字节

中等长度文本数据

LONGBLOB

0-4294967295字节

二进制形式的极大文本数据

LONGTEXT

0-4294967295字节

极大文本数据

CHAR和VARCHAR类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。

BINARY和VARBINARY类类似于CHAR和VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值字节的数值值。

BLOB是一个二进制大对象,可以容纳可变数量的数据。有4种BLOB类型: TINYBLOB、 BLOB、MEDIUMBLOB和LONGBLOB。它们只是可容纳值的最大长度不同。

有4种TEXT类型: TINYTEXT、 TEXT、MEDIUMTEXT和LONGTEXT。 这些对应4种BLOB类型,有相同的最大长度和存储需求。

4.2.2 非空约束

not null

CREATE TABLE student(
    id int primary key,
    name varchar(50) not null,
    sex varchar(10)
);

INSERT INTO student values(1,'tom',null);
4.2.3 默认值约束

default

CREATE TABLE student(
    id int primary key,
    name varchar(50) not null,
    sex varchar(10) default '男'
);

INSERT INTO student values(1,'marry','女');
INSERT INTO student values(2,'tom',default);
INSERT INTO student(id,name) values(1,'jack');

4.3 引用完整性

(参照完整性)

外键约束:FOREIGN KEY

示例:

#学生表
CREATE TABLE student(
    sid int primary key,
    name varchar(50) not null,
    sex varchar(10) default '男'
);
#成绩表
CREATE TABLE score(
    id int primary key,
    score int,
    sid int,
    CONSTRAINT fk_score_sid FOREIGN KEY(sid) REFERENCES student(sid)
);

#第二种写法(简写)
CREATE TABLE score(
    id int primary key,
    score int,
    sid int references student(sid),
);
-- 外键列的数据类型一定要与主键的类型一致

第二种添加外键方式。

#成绩表
CREATE TABLE score(
    id int primary key,
    score int,
    sid int,
);

ALTER TABLE score ADD  CONSTRAINT fk_score_sid FOREIGN KEY(sid) REFERENCES student(sid);

第五章 多表查询

多个表之间是有关系的,那么关系靠谁来维护?

多表约束:外键约束。

5.1 多表的关系

5.1.1 一对多关系

客户和订单,分类和商品,部门和员工。

一对多建表原则:在多的一方创建一个字段,字段作为外键指向一的一方的主键。

5.1.2 多对多关系

学生和课程:

多对多关系建表原则:需要创建第三张表,中间表至少两个字段,这两个字段分别作为外键指向各自一方的主键。

5.1.3 一对一关系

在实际开发中应用不多,因为一对一可以创建成一张表。

两种建表原则:

唯一外键对应:假设一对一是一个一对多的关系,在多的一方创建一个外键指向一的一方的主键,将外键设置为unique和 not null。

主键对应:让一对一的双方的主键进行建立关系。

5.2 多表查询

多表查询有如下几种:

  1. 合并结果集:UNION、UNION ALL
  2. 连接查询
    2.1内连接[INNER] JOIN ON
    2.2外连接OUTER JOIN ON
  • 左外连接LEFT [OUTER] JOIN
  • 右外连接RIGHT [OUTER] JOIN
  • 全外连接(MySQL不支持)FULL Join

2.3自然连接NATURAL JOIN

  1. 子查询
5.2.1 合并结果集

作用:合并结果集就是把两个select语句的查询结果合并到一起。

合并结果集有两种方式:

UNION:去除重复记录,例如

SELECT * FROM t1 UNION SELECT * FROM t2;


UNION ALL:不去除重复记录,例如:

SELECT * FROM t1 UNION ALL SELECT * FROM t2;


注意:被合并的两个结果:列数、列类型必须相同。

5.2.2 连接查询

连接查询就是求出多个表的乘积,例如t1连接t2,那么查询的结果就是t1*t2。


连接查询会产生笛卡尔积,假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1),(b,2)}。可以扩展到多个集合的情况。

那么多表查询产生这样的结果并不是我们想要的,那么怎么去除重复的,不想要的记录呢,当然是通过条件过滤。通常要查询的多个表之间都存在关联系,那么就通过关联关系去除笛卡尔积。

示例1:现有两张表

emp表:

CREATE TABLE emp(
    empno int,
    ename varchar(50),
    job varchar(50),
    mgr int,
    hiredate date,
    sal decimal(7,2),
    deptno int
);

dept表:

CREATE TABLE dept(
    deptno int,
    dname varchar(14),
    loc varchar(13)
);

执行如下语句:

SELECT * FROM emp,dept;


使用主外键关系作为条件来去除无用信息

SELECT * FROM emp,dept WHERE emp.deptno = dept.deptno;


上面查询会把两张表的所有列都查询出来,也许你不需要那么多列,这是就可以指定要查询的列了。

SELECT emp.ename,emp.sal,emp.comn,emp.deptno,emp.dname
FROM emp,dept
WHERE emp.deptno = dept.deptno;


一、内连接

上面的连接语句就是内连接,但它不是SQL标准中的查询方式。

SQL标准的内连接为:

SELECT *
FROM emp e
INNER JOIN dept d
ON e.deptno = d.deptno;

内连接的特点:查询结果必须满足条件。

二、外连接

包括左外连接和右外连接,外连接的特点:查询出的结果存在不满足条件的可能。

a、左外连接

SELECT * FROM emp e
LEFT OUTER JOIN dept d
ON  e.deptno = d.deptno;

左连接是先查询出左表(即以左表为主),然后查询右表,右表中满足条件的显示出来,不满足条件的显示NULL。

我们还是用上面的例子来说明。其中emp表中"Bob"这条记录中,部门编号为50, 而dept表中不存在部门编号为50的记录,所以“张三”这条记录,不能满足e.deptno=d.deptno这条件。 但在左连接中,因为emp表是左表,所以左表中的记录都会查询出来,即“Bob"这条记录也会查出,但相应的右表部分显示NULL。


b、右外连接

右连接就是先把右表中所有记录都查询出来,然后左表满足条件的显示,不满足显示NULL。例如在dept表中的40部门并不存在员工,但在右连接中,如果dept表为右表,那么还是会查出40部门,但相应的员工信息为NULL。

SELECT * FROM emp e
RIGHT OUTER JOIN dept d
ON e.deptno = d.deptno;


连接查询心得:

连接不限于两张表,连接查询也可以是三张、四张,甚至N张表的连接查询。通常连接查询不可能需要整个笛卡尔积,而只是需要其中一部分,那么这时就需要使用条件来去除不需要的记录。这个条件大多数情况下都是使用主外键关系去除。

两张表的连接查询一定有一个主外键关系,三张表的连接查询就一定有两个 主外键关系,所以在大家不是很熟悉连接查询时,首先要学会去除无用笛卡尔积,那么就是用主外键关系作为条件来处理。如果两张表的查询,那么至少有一个主外键条件,三张表连接至少有两个主外键条件。

5.2.3 子查询

一个select语句中包含另一个完整的select语句。

子查询就是嵌套查询,即SELECT中包含SELECT,如果一条语句中存在两个或两个以上的SELECT,那么就是子查询语句了。里面的查询叫做子查询,外层的查询叫父查询,一般情况都是先执行子查询再执行父查询。

子查询出现的位置:

  1. where后,作为被查询的条件的一部分;
  2. from后,作表。

当子查询出现在where后作为条件时,还可以使用如下关键字:

  1. any
  2. all

子查询结果集的形式:

  1. 单行单列(用于条件)
  2. 单行多列(用于条件)
  3. 多行单列(用于条件)
  4. 多行多列(用于表)

示例:

1、查询工资高于JONES的员工

分析:

查询条件:工资>JONES,其中JONES工资需要一条子查询

第一步:查询JONES的工资

SELECT sal FROM emp WHERE ename = 'JONES';

第二步:查询高于JONES工资的员工

SELECT * FROM emp WHERE sal > (第一步的结果);

结果:

SELECT * FROM emp WHERE sal > (SELECT sal FROM emp WHERE ename = 'JONES');

2、查询与SCOTT同一个部门的员工

子查询作为条件

子查询形式为单行单列

分析:

查询条件:部门=SCOTT的部门编号,其中SCOTT的部门编号需要一条子查询

第一步:查询SCOTT的部门编号

SELECT deptno FROM emp WHERE ename = 'SCOTT';

第二步:查询部门编号等于SCOTT的部门编号的员工

SELECT * FROM emp WHERE deptno = (SELECT deptno FROM emp WHERE ename = 'SCOTT');

3、工资高于30号部门所有人的员工信息

分析:

SELECT * FROM emp WHERE sal >(SELECT MAX(sal) FROM emp WHERE deptno = 30);

查询条件:工资高于30部门所有人工资,其中30号部门所有人工资是子查询,高于所有需要使用ALL关键字。

第一步:查询30号部门所有人工资

SELECT sal FROM emp WHERE deptno = 30;

第二步:查询高于30号部门所有人工资的员工信息

SELECT * FROM emp WHERE sal > ALL(第一步结果);

结果:

SELECT * FROM emp WHERE sal > ALL(SELECT sal FROM emp WHERE deptno = 30);

4、工资高于30号部门中任意一个人的员工信息

SELECT * FROM emp WHERE sal > ANY(SELECT sal FROM emp WHERE deptno = 30);

子查询作为条件

子查询形式为多行单列(当子查询结果集形式为多行单列时可以使用ALL或ANY关键字)

5、查询1982年后入职员工中工资最高的员工信息

SELECT *,MAX(sal) FROM (SELECT * FROM emp WHERE hiredate >= '1982-01-01') AS temp;
5.2.4 导出导入数据库

1、使用命令方式

导出数据库表:

mysqldump -u用户名 -p 数据库名 > 导出路径与文件名

导入数据库表:

mysql -u用户名 -p
mysql>use 数据库名
然后使用source命令,后面参数为脚本文件(如这里用到的.sql)
mysql>source 导出路径与文件名

2、使用工具导入导出工具

5.2.5 创建用户和授权

创建用户

CREATE USER  用户名及地址(`zhangsan`@`localhost`) IDENTIFIED BY 密码('123456');

授权

GRANT ALL(权限) ON school.*(数据库名.表名) TO `zhangsan`(用户名)

撤销授权

REVOKE ALL(权限) ON school.*(数据库名.表名) TO `zhangsan`(用户名);

删除用户

DROP USER `zhangsan`(用户名);