day03_MySQL约束 一. 单表查询(掌握) 1. 条件查询 1. 基本语法 where 字句后跟条件 2. 运算符 * < > <=>= <> * BETWEEN 值1 AND 等同于 值2>=值1 and <=值2 * IN(值1, 值2 . . . 值n) 等同于 =值1 OR =值2 OR = 值n * IS NULL 如果值为NULL, 要使用 ISNULL * IS NOT NULL 值不为NULL * AND && * OR || * NOT != * LIKE 模糊查询 2. 排序查询 基本语法: . . . orderby 字段 asc(desc) order by 排序字段1 排序方式1 排序字段2 排序方式2 ...; 排序方式: ASC : 升序, 默认的 DESC: 降序 注意事项: 如果有多个排序条件, 则当前面的条件值一样时, 才会去判断第二条件 案例: -- 按照数学成绩升序排列(默认ASC升序, DESC 降序) SELECT * FROM stuORDER BY math DESC; -- 按照数学成绩升序排序, 如果数学成绩一样, 则按照英语成绩排名 SELECT * FROM stuORDER BY math , english; 3. 聚合函数查询 将一列数据作为一个整体, 进行纵向的计算 1. count : 计算个数 1. 一般选择非空的列 : 主键 2. count(*) -- 查询个数 SELECT COUNT(id)FROM stu; SELECT COUNT(NAME)FROM stu; SELECTCOUNT(IFNULL(english,0)) FROM stu; SELECT COUNT(*)FROM stu; -- 不推荐 2. max : 计算最大值 -- 查询数学成绩最大值/最小值max /min SELECT MAX(math)FROM stu; 3. min : 计算最小值 4. sum : 计算和 -- 求和 SELECT SUM(math)FROM stu; 5. avg : 计算平均值 -- 求平均数 SELECT AVG(math)FROM stu; 注意事项: 聚合函数的计算, 排除null值 解决方案 : 1. 选择不包含非空的列进行计算 2. IFNULL函数 总结: 1. 聚合函数里面的参数 : 表的字段 2. 聚合函数在进行运算时, null值不会参与运算 3. 聚合函数一般是对 int 类型的进行运算, 其他类型的没有意义 4. 特别在使用 count(字段) 字段一般是主键字段(非空, 唯一) 4. 分组查询 1. 基本语法: group by 分组字段; select 字段名 [聚合函数] from 表名 [条件判断] group by 分组字段; 分组之后再进行判断 select 字段名 [聚合函数] from 表名 [条件判断] group by 分组字段 [HAVING 聚合函数查询]; 2. 注意事项 : 1. 分组之后查询的字段 : 分组字段, 聚合函数 2. where 和 having的区别? 1. where 在分组之前进行限定, 如果不满足条件, 则不参与分组, having 在分组之后进行限定 2. where 后不可以跟聚合函数, having 可以进行聚合函数的判断 3. 总结: 1. 分组字段数据要有共同特点 2. 分组查询时, select 分组字段, 聚合字段 from . . . 3. 查询操作是, 关键字的先后顺序: select 字段 from 表名 where 分组前条件判断 group by 分组字段 having 分组后的条件判断 order by 排序查询 案例: -- 分组查询, 按照性别查询(男, 女 分开)平均分, 分别的人数是多少 SELECT sex,AVG(math) FROM stu GROUP BY sex; -- 分组查询, 按照性别查询(男, 女 分开)平均分, 分别的人数是多少 SELECT sex,AVG(math), COUNT(id) FROM stu GROUP BY sex; -- 分组查询, 按照性别查询(男, 女 分开)平均分, 分别的人数, 分数低于70分的人不参与分组 SELECT sex,AVG(math), COUNT(id) FROM stu WHERE math > 70 GROUP BY sex; -- 分组查询, 按照性别查询(男, 女 分开)平均分, 分别的人数, 分数低于70分的人不参与分组, 分组之后人数要大于2个人 SELECT sex,AVG(math), COUNT(id) FROM stu WHERE math > 70 GROUP BY sex HAVING COUNT(id) >2; 5. 分页查询 数据太多, 一次性查询出来后, 展示效果不好, 就是用户的体验不好 分页操作, 不同的数据库分页基本原理不一样 mysql: limit 进行分页, 奇特数据库不能使用limit 进行分页 1. 语法 : limit 开始的索引,每页查询的条数 开始的索引从 0 开始, 表示第一条记录 2. 公式 : 公式 : 开始的索引 = (当前的页码 - 1) * 每页显示的条数 3. 分页操作是一个"方言" 案例: -- 每页显示3条记录 SELECT * FROM stu LIMIT0,3; -- 第1页 SELECT * FROM stuLIMIT 3,3; -- 第2页 SELECT * FROM stuLIMIT 6,3; -- 第3页 -- 公式 : 开始的索引 = (当前的页码 - 1) * 每页显示的条数 综合案例: -- 员工表 CREATE TABLE `emp`( `empno` INT(11)NOT NULL, `ename`VARCHAR(50) DEFAULT NULL, `job` VARCHAR(50)DEFAULT NULL, `mgr` INT(11)DEFAULT NULL, `hiredate` DATEDEFAULT NULL, `sal` DECIMAL(7,2)DEFAULT NULL, `COMM`DECIMAL(7,2) DEFAULT NULL, `deptno` INT(11)DEFAULT NULL, PRIMARY KEY(`empno`), KEY `fk_emp`(`mgr`), CONSTRAINT`fk_emp` FOREIGN KEY (`mgr`) REFERENCES `emp` (`empno`) ) ENGINE=INNODBDEFAULT CHARSET=utf8; INSERT INTO empVALUES (1009, '曾阿牛', '董事长', NULL, '2001-11-17', 50000, NULL, 10); INSERT INTO empVALUES (1004, '刘备', '经理', 1009, '2001-04-02', 29750, NULL, 20); INSERT INTO empVALUES (1006, '关羽', '经理', 1009, '2001-05-01', 28500, NULL, 30); INSERT INTO empVALUES (1007, '张飞', '经理', 1009, '2001-09-01', 24500, NULL, 10); INSERT INTO empVALUES (1008, '诸葛亮', '分析师', 1004, '2007-04-19', 30000, NULL, 20); INSERT INTO empVALUES (1013, '庞统', '分析师', 1004, '2001-12-03', 30000, NULL, 20); INSERT INTO empVALUES (1002, '黛绮丝', '销售员', 1006, '2001-02-20', 16000, 3000, 30); INSERT INTO empVALUES (1003, '殷天正', '销售员', 1006, '2001-02-22', 12500, 5000, 30); INSERT INTO empVALUES (1005, '谢逊', '销售员', 1006, '2001-09-28', 12500, 14000, 30); INSERT INTO empVALUES (1010, '韦一笑', '销售员', 1006, '2001-09-08', 15000, 0, 30); INSERT INTO empVALUES (1012, '程普', '文员', 1006, '2001-12-03', 9500, NULL, 30); INSERT INTO empVALUES (1014, '黄盖', '文员', 1007, '2002-01-23', 13000, NULL, 10); INSERT INTO empVALUES (1011, '周泰', '文员', 1008, '2007-05-23', 11000, NULL, 20); INSERT INTO empVALUES (1001, '甘宁', '文员', 1013, '2000-12-17', 8000, NULL, 20); -- 用户表 CREATE TABLE`tab_user` ( `id` INT(11)DEFAULT NULL, `username`VARCHAR(32) DEFAULT NULL, `address`VARCHAR(32) DEFAULT NULL, `password`VARCHAR(32) DEFAULT NULL ) ENGINE=INNODBDEFAULT CHARSET=utf8; INSERT INTO`tab_user`(`id`,`username`,`address`,`password`) VALUES (2,'b','tj','a'),(3,'c','tj','a'),(4,'d','tj','a'),(5,'e','tj','a'),(6,'f','tj','a'),(7,'t','tj','a'),(8,'k','tj','a'),(9,'l','tj','a'),(10,'jack','tj','a'),(11,'船长','tj','a'),(12,'rose','tj','a'),(13,'王琦','tj','a'),(14,'张五','tj','a'),(1,'a','tj','c'); SELECT * FROM emp;-- 查询表 -- 查询 薪水介于 8000到16000之间的员工的姓名 和工作 薪水(两种方式) SELECT ename, job,sal FROM emp WHERE sal>=8000AND sal<=16000; SELECT ename, job,sal FROM emp WHERE sal BETWEEN8000 AND 16000; -- 查询 受雇日期是 2000-12-17, 2001-02-20的员工的姓名和受雇日期(两种方式) SELECT ename,hiredate FROM emp WHERE hiredate ='2000-12-17' OR hiredate = '2001-02-20'; SELECT ename,hiredate FROM emp WHERE hiredate IN('2000-12-17' , '2001-02-20'); -- 查询 工作不是文员的 薪水总和 SELECT SUM(sal) FROM emp WHERE job != '文员'; -- 查询受雇日期 早于 2007-05-23的 员工的薪水总和 SELECT SUM(sal) AS员工的薪水总和 FROM emp WHERE hiredate<= '2007-05-23'; -- 查询 每一种工作的薪水总和 SELECT job,SUM(sal) AS 薪水总和 FROM emp GROUP BY job; -- 查询 工作不是文员的 每一种工作的薪水总和 SELECT job,SUM(sal) AS 薪水总和 FROM emp WHERE job != '文员' GROUP BY (job); -- 查询 受雇日期 2007-05-23的 员工, 并且按照部门分组, 查询每个部门的薪水总和 SELECT deptno,SUM(sal) AS 薪水总和 FROM emp WHERE hiredate<= '2007-05-23' GROUP BY deptno; -- 查询 受雇日期 2007-05-23的 员工, 并且按照部门分组, 查询每个部门的薪水总和, 且部门的总薪水大于90000 SELECT deptno,SUM(sal) AS 薪水总和 FROM emp WHERE hiredate<= '2007-05-23' -- 分组前条件 GROUP BY deptno --分组字段 HAVING SUM(sal)> 90000; -- 分组后条件, 之后分完组后, 才能求每个部门的总薪水 -- 查询 受雇日期 2007-05-23的 员工, 并且按照部门分组, 查询每个部门的薪水总和, 且部门的总薪水大于25000, 最终按照总薪水的大小进行降序排列 SELECT deptno,SUM(sal) AS 薪水总和 FROM emp WHERE hiredate<= '2007-05-23' GROUP BY deptno HAVING SUM(sal)>90000 ORDER BYSUM(sal)DESC; -- 对最终符合条件的数据进行排序 二. 约束(掌握) 1. 概述: 对表中的数据进行限定, 保证数据的的正确性, 有效性和完整性 一种规范(限制), 数据库约束就是对表中的数据进行规范, 让数据具有某种特点 2. 分类: 1. 主键约束 : primary key 2. 非空约束: not null 3. 唯一约束: unique 4. 外键约束: foreign key * 非空约束: not null 1. 创建表时添加约束 CREATE TABLE stu( id INT, NAME VARCHAR(20)NOT NULL ); 2. 创建表完后, 添加非空约束 ALTER TABLE stuMODIFY NAME VARCHAR(20) NOT NULL; 3. 创建表完后, 去除非空约束 ALTER TABLE stuMODIFY NAME VARCHAR(20); * 唯一约束: unique, 某一列的值不能重复 1. 注意事项: 唯一约束可以有NULL值, 但是只能有一条记录为null 2. 在创建表时, 添加唯一约束 CREATE TABLE stu2( id INT, phone_numberVARCHAR(20) UNIQUE -- 添加唯一约束 ); 3. 删除唯一约束 ALTER TABLE stu2DROP INDEX phone_number; 4. 在表创建完后, 添加唯一约束 ALTER TABLE stu2MODIFY phone_number VARCHAR(20) UNIQUE; * 主键约束: primary key 1. 注意事项: 1. 含义: 非空且唯一 2. 一张表只能有一个字段主键 3. 主键就是表中记录的唯一 2. 在创建表时, 添加主键 CREATE TABLE stu3( id INT PRIMARYKEY,-- 给id添加主键约束 NAME VARCHAR(20) ); 3. -- 删除主键 ALTER TABLE stu3DROP PRIMARY KEY; 4. -- 创建完表后, 添加主键 ALTER TABLE stu3MODIFY id INT PRIMARY KEY; 5. 自动增长: 概念: 如果某一列是数值类型的, 使用 auto_increment 可以来完成值的自动增长 -- 创建表时添加自动增长 CREATE TABLE stu4( id INT PRIMARY KEYAUTO_INCREMENT,-- 给id添加主键约束 NAME VARCHAR(20) ); -- 删除自动增长 ALTER TABLE stu4MODIFY id INT; -- 添加自动增长 ALTER TABLE stu4MODIFY id INT AUTO_INCREMENT; * 外键约束 :foreign key , 让表与表产生关系, 从而保证数据的正确性 1. 在创建表时, 添加外键 语法: create table 表名 { . . . 外键列 constraint 外键名称 foreign key (外键列的名称) references 主表名称(主表列名称) }; 2. 删除外键: ALTER TABLE 表名 DROP FOREIGN KEY 外键名称; 3. 添加外键: ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名称) REFERENCES 主表名称(主表列名称) 4. 外键的特点: 1. 外键的值不能随意写 2. 外键的值引用于另一张表的主键值 3. 外键的值可以为null , 但是为null没有任何意义 5. 外键的设计原则 主表 子表 6. 级联操作 : 只有表与表之间有关联关系, 才能进行级联操作 作用: 当主表的数据发生变化时, 那么字表的数据会级联发生变化 级联操作: 一般情况下, 操作是对修改(update)和删除(delete) 分两种情况: 1. 当主表的数据变化时, 子表的数据保持一致 on update cascade on update cascade 2. 当主表的数据变化时, 子表的数据(外键的数据) 设置为null 语法: on updateset null on delete set null 1. 添加级联操作 语法:ALTER TABLE 表名 ADD CONSTRAINT 外键名称 OREIGN KEY (外键字段名称) REFERENCES 主表名称(主表列名称) ON UPDATE CASCADE ON DELETE CASCADE ; 2. 分类: 1. 级联更新:ON UPDATE CASCADE 2. 级联删除:ON DELETE CASCADE 三 数据库的设计 多表之间的关系 1. 一对一 : (了解, 很少存在) 如: 人和身份证的关系 分析: 一个人只有一个身份证, 一个身份证只能对应一个人 如: 用户表和 信息表 主表(子表)可以是任意一方 2. 一对多(多对一) : 如: 部门表和 员工表 分析: 一个部门有多个员工, 一个员工只能对应一个部门 主表: 一方表, 这里值的就是部门表 子表: 多方表, 这里指的就是员工表 外键设计在子表里面 3. 多对多: (通俗的来说, 是强化版的一对一) 如: 学生表和 课程表 分析: 一个学生可以选择很多门课程, 一个课程也可以被很多学生选择 主表(子表) 可以是任意一方 (不推荐这样区分和设计外键) 数据库设计的范式 1. 概念: 设计数据库时, 需要遵循的一些规范, 要遵循后边的范式要求, 必须先遵循前边的所有 设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。 2. 分类: 第一范式(1NF):每一列都是不可分割的原子数据项 第二范式(2NF):在1NF的基础上,非码属性必须完全依赖于码(在1NF基础上消除非主属性对主码的部分函数依赖) 几个概念: 函数依赖:A-->B,如果通过A属性(属性组)的值,可以确定唯一B属性的值。则称B依赖于A 例如:学号-->姓名。(学号,课程名称) --> 分数 完全函数依赖:A-->B,如果A是一个属性组,则B属性值得确定需要依赖于A属性组中所有的属性值。 例如:(学号,课程名称)--> 分数 部分函数依赖:A-->B,如果A是一个属性组,则B属性值得确定只需要依赖于A属性组中某一些值即可。 例如:(学号,课程名称)-- > 姓名 传递函数依赖:A-->B,B -- >C . 如果通过A属性(属性组)的值,可以确定唯一B属性的值,在通过B属性(属性组)的值可以确定唯一C属性的值,则称 C 传递函数依赖于A 例如:学号-->系名,系名-->系主任 码:如果在一张表中,一个属性或属性组,被其他所有属性所完全依赖,则称这个属性(属性组)为该表的码 例如:该表中码为:(学号,课程名称) * 主属性:码属性组中的所有属性 * 非主属性:除过码属性组的属性 第三范式(3NF):在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖) 四 数据库的备份与还原 1. 命令行: 语法: 备份 : mysqldump-u用户名 -p密码 数据库名 > 保存路径 还原 : 1. 登录数据库 2. 创建数据库 3. 使用数据库 4. 执行文件。source 文件路径 2. 图形化工具: 案例 SHOW DATABASES; -- 查询数据库 SHOW CREATE DATABASE db1; SHOW TABLES; -- 查询表格 DESC stu; -- 查询表格结构 TRUNCATE TABLE stu; CREATE TABLE stu ( id INT, -- 编号 NAME VARCHAR(20), -- 姓名 age INT, -- 年龄 sex VARCHAR(5), -- 性别 address VARCHAR(100), -- 地址 math INT, -- 数学 english INT -- 英语 ); INSERT INTO stu(id,NAME,age,sex,address,math,english) VALUES (1,'马云',55,'男', '杭州',66,78), (2,'马化腾',45,'女','深圳',98,87), (3,'马景涛',55,'男','香港',56,77), (4,'柳岩',20,'女','湖南',76,65), (5,'柳青',20,'男','湖南',86,NULL), (6,'刘德华',57,'男','香港',99,99), (7,'马德',22,'女','香港',99,99), (8,'德玛西亚',18,'男','南京',56,65); SHOW TABLES; SELECT * FROM stu; -- 查询表格 TRUNCATE stu; -- 删除所有数据并创建一个一模一样的表格 SELECT id 学号, -- 学号 NAME 姓名, -- 姓名 age 年龄, -- 年龄 sex 性别, -- 性别 address 地址, -- 地址 math 数学成绩, -- 数学成绩 english 英语成绩 -- 英语成绩 FROM stu; -- 去除重复的结果集 SELECT DISTINCT address FROM stu; -- 查询地址 SELECT DISTINCT NAME,address FROM stu; -- 查询地址 -- 计算 math 和English 分数之和 SELECT NAME,math,english,math + english FROM stu; -- 如果有null参与的运算, 计算结果都为null SELECT NAME,math,english,math + IFNULL(english,0) FROMstu; -- 起别名 SELECT NAME,math 数学,english 英语,math + IFNULL(english,0) 总分 FROM stu; -- 查询年龄大于20岁的 SELECT * FROM stu WHERE age > 20; -- 查询年龄等于20岁的 SELECT * FROM stu WHERE age = 20; -- 查询年龄不等于20岁的 SELECT * FROM stu WHERE age != 20; -- 查询年龄大于等于20岁 小于等于30的 SELECT * FROM stu WHERE age >=20 AND age <=30; SELECT * FROM stu WHERE age BETWEEN 20 AND 30; -- 查询年龄22岁, 18岁, 25岁的信息 SELECT * FROM stu WHERE age = 22 OR age = 18 OR age =25; SELECT * FROM stu WHERE age IN(18,22,25); SELECT * FROM stu WHERE age IN(18,22,25) AND sex = '女'; -- 查询英语成绩是null的 SELECT * FROM stu WHERE english = NULL; -- 不对的, null值不能使用=(!=) 去判断 SELECT * FROM stu WHERE english IS NULL; -- 查询英语成绩不是null的 SELECT * FROM stu WHERE english IS NOT NULL; -- 查询姓马的有哪些? SELECT * FROM stu WHERE NAME LIKE '马%'; -- 查询第二个字是化的人 SELECT * FROM stu WHERE NAME LIKE "_化%"; -- 查询姓名是三个字的人 SELECT * FROM stu WHERE NAME LIKE '___'; -- 查询姓名中包含德的人 SELECT * FROM stu WHERE NAME LIKE '%德%'; SELECT * FROM stu; -- 查询表 -- 按照数学成绩升序排列(默认ASC 升序, DESC 降序) SELECT * FROM stu ORDER BY math DESC; -- 按照数学成绩升序排序, 如果成绩一样则按照英语成绩排名 SELECT * FROM stu ORDER BY math , english; -- 查询个数 SELECT COUNT(IFNULL(english,0)) FROM stu; SELECT COUNT(*) FROM stu; -- 不推荐 -- 查询数学成绩最大值/最小值 max /min SELECT MAX(math) FROM stu; -- 求和 SELECT SUM(math) FROM stu; -- 求平均数 SELECT AVG(math) FROM stu; -- 分组查询, 按照性别查询(男, 女分开)平均分, 分别的人数是多少 SELECT sex, AVG(math) FROM stu GROUP BY sex; -- 分组查询, 按照性别查询(男, 女分开)平均分, 分别的人数是多少 SELECT sex, AVG(math), COUNT(id) FROM stu GROUP BYsex; -- 分组查询, 按照性别查询(男, 女分开)平均分, 分别的人数,分数低于70分的人不参与分组 SELECT sex, AVG(math), COUNT(id) FROM stu WHERE math> 70 GROUP BY sex; -- 分组查询, 按照性别查询(男, 女分开)平均分, 分别的人数,分数低于70分的人不参与分组, 分组之后人数要大于2个人 SELECT sex, AVG(math), COUNT(id) FROM stu WHERE math> 70 GROUP BY sex HAVING COUNT(id) > 2; -- SELECT * FROM stu; -- 每页显示3条记录 SELECT * FROM stu LIMIT 0,3; -- 第1页 SELECT * FROM stu LIMIT 3,3; -- 第2页 -- 公式 : 开始的索引 = (当前的页码 -1) * 每页显示的条数 CREATE TABLE IF NOT EXISTS tab_stu2( id INT, NAME VARCHAR(20) NOT NULL -- name 为非空 ); SELECT * FROM tab_stu2; -- 查询表格 INSERT INTO tab_stu2 VALUE(2,'张无忌'); INSERT INTO tab_stu2 VALUE(3, NULL); DELETE FROM tab_stu2 WHERE id =3; ALTER TABLE tab_stu2 MODIFY `name` VARCHAR(32) NOTNULL; SELECT * FROM tab_stu3; -- 查询表格 CREATE TABLE tab_stu3( id INT, phone_number VARCHAR(20) UNIQUE-- 手机号 ); INSERT INTO tab_stu3 VALUE (1,'123'); INSERT INTO tab_stu3 VALUE (2,NULL); SELECT * FROM tab_stu4; -- 添加主键约束 CREATE TABLE tab_stu4( id INT PRIMARY KEY, NAME VARCHAR(32) ); -- 删除主键 -- alter table tab_stu4 id int; -- 错误的 ALTER TABLE tab_stu4 DROP PRIMARY KEY; -- 添加主键 ALTER TABLE tab_stu4 MODIFY id INT PRIMARY KEY; CREATE TABLE tab_stu5( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(32) ); SELECT * FROM tab_stu5; -- 删除自动增长 ALTER TABLE tab_stu5 MODIFY id INT; -- 添加自动增长 ALTER TABLE tab_stu5 MODIFY id INT AUTO_INCREMENT;
|