🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 数据库小结 ## 数据库相关概念 ​ 1、DB:数据库,保存一组有组织的数据的容器 2、DBMS:数据库管理系统,又称为数据库软件(产品),用于管理DB中的数据 3、SQL:结构化查询语言,用于和DBMS通信的语言 ## 数据库存储数据的特点 ​ 1、将数据放到表中,表再放到库中 2、一个数据库中可以有多个表,每个表都有一个的名字,用来标识自己。表名具有唯一性。 3、表具有一些特性,这些特性定义了数据在表中如何存储,类似java中 “类”的设计。 4、表由列组成,我们也称为字段。所有表都是由一个或多个列组成的,每一列类似java 中的”属性” 5、表中的数据是按行存储的,每一行类似于java中的“对象”。 ## MySQL服务的启动和停止 ​ 方式一:计算机——右击管理——服务 方式二:通过管理员身份运行 net start 服务名(启动服务) net stop 服务名(停止服务) ## MySQL服务的登录和退出 ```mysql 方式一:通过mysql自带的客户端 只限于root用户 方式二:通过windows自带的客户端 登录: mysql 【-h主机名 -P端口号 】-u用户名 -p密码 mysql -u root -p 以root用户登录 退出: exit或ctrl+C ``` ## 在端口中MySQL的常见命令 ```mysql 1.查看当前所有的数据库 show databases; 2.打开指定的库 use 库名; 3.查看当前库的所有表 show tables; 4.查看其它库的所有表 show tables from 库名; 5.创建表 create table 表名( 列名 列类型, 列名 列类型, 。。。 ); 6.查看表结构 desc 表名; 解决中文乱码问题:set names gbk; 7.删除信息 delete from 表名 where 条件 8.插入信息 insert into 表名 (字段1,字段2,...) values() 9.更新/修改信息 update 表名 set 条件 10.查询信息 select * from 表名 ;* 表示所有信息,也可以只查几个信息 ``` ```mysql 11.查看服务器的版本 方式一:登录到mysql服务端 select version(); 方式二:没有登录到mysql服务端 mysql --version 或 mysql --V ``` ## MySQL的语法规范 ​ 1.不区分大小写,但建议关键字大写,表名、列名小写 2.每条命令最好用分号结尾 3.每条命令根据需要,可以进行缩进 或换行 4.注释 单行注释:#注释文字 单行注释:-- 注释文字 多行注释:/* 注释文字 */ ## 数据库查询语句学习 ### 1 基础查询 语法: SELECT 要查询的东西 【FROM 表名】; 特点: 1、查询列表可以是:表中的字段、常量值、表达式、函数 2、查询的结果是一个虚拟的表格 ```mysql 1.查询表中的单个字段 查询员工的姓 SELECT last_name FROM employees 2.查询表中的多个字段 查询员工的姓,工资,email SELECT last_name,salary,email FROM employees 3.查询表中的所有字段 查询员工所有信息 select * from employees ``` ### 2 条件查询 条件查询:根据条件过滤原始表的数据,查询到想要的数据 语法: select 要查询的字段|表达式|常量值|函数 from 表 where 条件 ; ```mysql 1.等值条件 = 等于 <>不等于 查询员工号为125的员工名与工资 select first_name,salary from employees where employee_id=125 2.< > <= >=条件 查询部门id大于50的员工信息 select * from employees where department_id>50 3.逻辑连接条件 查询部门号为50的并且名字中含有u的员工信息 select * from employees where department_id=50 and first_name like '%u%' 逻辑运算符有三种: and(&&):两个条件如果同时成立,结果为true,否则为false or(||):两个条件只要有一个成立,结果为true,否则为false not(!):如果条件成立,则not后为false,否则为true 4. 1 0 条件 在SQL中, 1表示 true, 0表示 false select * from employees where 1 该语句会执行 5.模糊查询条件,四个关键字 a like:特点:一般和通配符搭配使用 通配符: % 任意多个字符,包含0个字符 _ 任意单个字符 案例1:查询员工名中包含字符a的员工信息 select * from employees where last_name like '%a%' b between and 特点:使用between and 可以提高语句的简洁度 包含临界值 两个临界值不要调换顺序 案例:查询员工编号在100到120之间的员工信息 SELECT * FROM employees WHERE employee_id >= 120 AND employee_id<=100 c in 含义:判断某字段的值是否属于in列表中的某一项 特点:使用in提高语句简洁度 in列表的值类型必须一致或兼容 in列表中不支持通配符 案例:查询员工的工种编号是 IT_PROG、AD_VP、AD_PRES中的一个员工名和工种编号 方法一 SELECT last_name,job_id FROM employees WHERE job_id = 'IT_PROT' OR job_id = 'AD_VP' OR JOB_ID ='AD_PRES' 方法二 SELECT last_name,job_id FROM employees WHERE job_id IN( 'IT_PROT' ,'AD_VP','AD_PRES') d is null =或<>不能用于判断null值 is null或is not null 可以判断null值 案例:查询没有奖金的员工名和奖金率 SELECT last_name,commission_pct FROM employees WHERE commission_pct IS NULL IS NULL:仅仅可以判断NULL值,可读性较高,建议使用 <=> :既可以判断NULL值,又可以判断普通的数值,可读性较低 ``` ### 3 排序查询 **关键字段:order by** 语法: select 要查询的东西 from 表 where 条件 order by 排序的字段|表达式|函数|别名 【asc|desc】 **ASC 表示升序,默认,可以不写** **DESC 表示降序** **order by子句在查询语句的最后面,除了limit子句** ```mysql 1、按单个字段排序 #按员工工资降序排序 SELECT * FROM employees ORDER BY salary DESC 2、添加筛选条件再排序 #查询部门编号>=90的员工信息,并按员工编号降序 SELECT * FROM employees WHERE department_id>=90 ORDER BY employee_id DESC 3、按表达式排序 #查询员工信息 按年薪降序 SELECT *,salary*12*(1+IFNULL(commission_pct,0)) FROM employees ORDER BY salary*12*(1+IFNULL(commission_pct,0)) DESC 4、按别名排序 #查询员工信息 按年薪升序 SELECT *,salary*12*(1+IFNULL(commission_pct,0)) 年薪 FROM employees ORDER BY 年薪 ASC 5、按函数排序 #查询员工名,并且按名字的长度降序 SELECT LENGTH(last_name),last_name FROM employees ORDER BY LENGTH(last_name) DESC 6、按多个字段排序 #查询员工信息,要求先按工资降序,再按employee_id升序 SELECT * FROM employees ORDER BY salary DESC,employee_id ASC -- 多字段排序,谁写在前面就一谁为主排序,再以后面字段排序 ``` ### 4 分组函数 **特点:** 1、sum、avg一般用于处理数值型 max、min、count可以处理任何类型 2、以上**分组函数都忽略null值** **(除了count(*))** 3、可以和distinct搭配实现去重的运算 4、count函数的单独介绍 一般使用count(*)用作统计行数 5、**和分组函数一同查询的字段要求是group by后的字段** **功能:用作统计使用,又称为聚合函数或统计函数或组函数** **分类:** **sum 求和、avg 平均值、max 最大值 、min 最小值 、count 计算个数** ```mysql 1、简单的使用 SELECT SUM(salary) FROM employees; SELECT AVG(salary) FROM employees; SELECT MIN(salary) FROM employees; SELECT MAX(salary) FROM employees; SELECT COUNT(salary) FROM employees; SELECT SUM(salary) 和,AVG(salary) 平均,MAX(salary) 最高,MIN(salary) 最低,COUNT(salary) 个数 FROM employees; 2、忽略 null 值 -- 使用分组函数时会忽略表中的 null 值的信息 3、 distinct 搭配 # 1000 1000 2000 2000 2000 5000 5000 # 1000 2000 5000 8000 SELECT SUM(DISTINCT salary),SUM(salary) FROM employees 4、 count函数的介绍 SELECT COUNT(salary) FROM employees; SELECT COUNT(*) FROM employees; #在每一条信息前面加一个*,计算*的总数 ``` ### 5 常见函数 概念:类似于java的方法,将一组逻辑语句封装在方法体中,对外暴露方法名 **好处:1、隐藏了实现细节 2、提高代码的重用性** **调用:select 函数名(实参列表) 【from 表】** #### 5类常见函数 ##### 1、字符函数 ```mysql concat 拼接 #concat(字段1,字段2,..) SELECT CONCAT(last_name,'_',first_name) 姓名 FROM employees substr截取子串 select substr('你伤害了我,还一笑而过',5) #表示从第五个索引值开始截取,下标从1开始 select substr('你伤害了我,还一笑而过',1,5) #表示从第一个索引值开始截取,截取长度为3 upper转换成大写 lower转换成小写 #案例:姓名中首字符大写,其他字符小写然后用_拼接,显示出来 SELECT CONCAT(UPPER(SUBSTR(last_name,1,1)),'_',LOWER(SUBSTR(last_name,2))) FROM employees trim去前后指定的空格和字符 SELECT LENGTH(TRIM(' 张翠山 ')) ; #去掉前后空格 SELECT TRIM('aa' FROM 'aaaaaaaaa张aaaaaaaaaaaa翠山aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa') ; #去掉前后 aa,奇数就留一个,偶数全去掉 replace替换 SELECT REPLACE('来吧来吧相约98,来吧来吧,相约98','98','酒吧') #将文字中的98替换为酒吧,传3个参数 lpad左填充 rpad右填充 SELECT LPAD('变形金刚',2,'*') -- 变形 SELECT RPAD('变形金刚',2,'*') -- 变形 #也能实现截取,但不管lpad还是rpad都是从左边开始截取 instr返回子串第一次出现的索引 length 获取字节个数(utf-8一个汉字代表3个字节,gbk为2个字节) #length 获取参数值的字节个数 SELECT LENGTH('john');-- 4 SELECT LENGTH('张三丰hahaha') -- 15 ``` ##### 2、数学函数 ```mysql round 四舍五入 SELECT ROUND(-1.55);-- -2 SELECT ROUND(1.567,2);-- 1.57 rand 随机数 floor向下取整 #返回<=该参数的最大整数 SELECT FLOOR(-9.99) -- -10 ceil向上取整 #返回>=该参数的最小整数 SELECT CEIL(-1.02) -- -1 mod取余 #mod(a,b) SELECT mod(-10,3) -- -1 #除数有误负号都会被忽略,当被除数有负号时,余数也有负号, truncate截断 #截取小数点个数 SELECT TRUNCATE(1.69999,1); -- 1.6 ``` ##### 3、日期函数 ```mysql now当前系统日期+时间 SELECT NOW(); curdate当前系统日期 SELECT CURDATE(); curtime当前系统时间 SELECT CURTIME(); str_to_date 将字符转换成日期 #str_to_date 将字符通过指定的格式转换成日期 SELECT STR_TO_DATE('1998-3-2','%Y-%c-%d') AS out_put; date_format将日期转换成字符 SELECT DATE_FORMAT(NOW(),'%y年%m月%d日') AS out_put; ``` ##### 4、流程控制函数 ```mysql 1 if 处理双分支 SELECT IF(10<5,'大','小'); #如果判断为 true,输出前面的参数,false输出后面的参数 2 case语句 处理多分支 情况1:处理等值判断 情况2:处理条件判断 /*案例:查询员工的工资,要求 部门号=30,显示的工资为1.1倍 部门号=40,显示的工资为1.2倍 部门号=50,显示的工资为1.3倍 其他部门,显示的工资为原工资 */ SELECT salary 原始工资,department_id, CASE department_id WHEN 30 THEN salary*1.1 WHEN 40 THEN salary*1.2 WHEN 50 THEN salary*1.3 ELSE salary END AS 新工资 FROM employees; #条件结束后,要用 end 结尾 再起个别名 ``` ##### 5、其他函数 ```mysql SELECT VERSION(); -- 查看版本 SELECT DATABASE(); -- 查看数据库 SELECT USER(); -- 查看用户 ``` ### 6 分组查询 **关键字段:GROUP BY** 语法: select 查询列表 from 表 【where 筛选条件】 group by 分组的字段 【order by 排序的字段】 特点: 1、和分组函数一同查询的字段必须是group by后出现的字段 2、筛选分为两类:分组前筛选和分组后筛选 连接的关键字 分组前筛选 原始表 group by前 where 分组后筛选 group by后的结果集 group by后 having ```mysql -- where having 有什么区别 ? -- where 主要用来对原始表中 有的字段 进行筛选 。 -- having 主要对原始表中不存在的字段 进行筛选 。 -- where 放在 group by 前面 -- having 放在 group by 后面 。 基本上只用在分组函数。 #案例 查询每个工种的员工平均工资 SELECT AVG(salary),job_id FROM employees GROUP BY job_id; #案例 查询邮箱中包含a字符的 每个部门的最高工资 SELECT MAX(salary),department_id FROM employees WHERE email LIKE '%a%' GROUP BY department_id; #案例:查询哪个部门的员工个数>5 SELECT COUNT(*),department_id FROM employees GROUP BY department_id HAVING COUNT(*)>5; #按多个字段分组 #案例:查询每个工种每个部门的最低工资,并按最低工资降序 SELECT MIN(salary),job_id,department_id FROM employees GROUP BY department_id,job_id ORDER BY MIN(salary) DESC; ``` ### 7 多表连接查询 ```mysql -- 笛卡尔乘积:如果连接条件省略或无效则会出现 -- 解决办法:添加上连接条件 ``` #### 一、传统模式下的连接 :等值连接——非等值连接 1.等值连接的结果 = 多个表的交集 2.n表连接,至少需要n-1个连接条件 3.多个表不分主次,没有顺序要求 4.一般为表起别名,提高阅读性和性能 #### 二、sql99语法:通过join关键字实现连接 含义:1999年推出的sql语法 支持: 等值连接、非等值连接 (内连接) 外连接 交叉连接 语法: select 字段,... from 表1 【inner|left outer|right outer|cross】join 表2 on 连接条件 【inner|left outer|right outer|cross】join 表3 on 连接条件 【where 筛选条件】 【group by 分组字段】 【having 分组后的筛选条件】 【order by 排序的字段或表达式】 好处:语句上,连接条件和筛选条件实现了分离,简洁明了! #### 三、自连接 案例:查询员工名和直接上级的名称 sql99 SELECT e.last_name,m.last_name FROM employees e JOIN employees m ON e.`manager_id`=m.`employee_id`; sql92 SELECT e.last_name,m.last_name FROM employees e,employees m WHERE e.`manager_id`=m.`employee_id`; ### 8 子查询 含义:一条查询语句中又嵌套了另一条完整的select语句,其中被嵌套的select语句,称为子查询或内查询 在外面的查询语句,称为主查询或外查询 特点: 1、子查询都放在小括号内 2、子查询可以放在from后面、select后面、where后面、having后面,但一般放在条件的右侧 3、子查询优先于主查询执行,主查询使用了子查询的执行结果 4、子查询根据查询结果的行数不同分为以下两类: ① 单行子查询 结果集只有一行 一般搭配单行操作符使用:> < = <> >= <= 非法使用子查询的情况: a、子查询的结果为一组值 b、子查询的结果为空 ② 多行子查询 结果集有多行 一般搭配多行操作符使用:any、all、in、not in in: 属于子查询结果中的任意一个就行 any和all往往可以用其他查询代替 ```sql 分类: 按子查询出现的位置: select后面: 仅仅支持标量子查询 from后面: 支持表子查询 一般用完之后都要给子查询起一个别名,把这个别名当做一张表来看。 where或 having 后面:★ 标量子查询(单行) √ 列子查询 (多行) √ 行子查询 SQL ... exists 后面(相关子查询) 表子查询 按结果集的行列数不同: 标量子查询(结果集只有一行一列) 列子查询(结果集只有一列多行) 行子查询(结果集有一行多列) 表子查询(结果集一般为多行多列) ``` ```mysql where或 having后面 /* 1、标量子查询(单行子查询) 2、列子查询(多行子查询) 3、行子查询(多列多行) 特点: ①子查询放在小括号内 () ②子查询一般放在条件的右侧 工资>(子查询) king 所有员工的名字,部门id... ③标量子查询,一般搭配着单行操作符使用 > < >= <= = <> 列子查询,一般搭配着多行操作符使用 in、any/some、all in ( ) any ( ) 匹配任意一个 , some 匹配任意一个 salary>any (5000,6000,8000) all () 匹配所有 。 */ #1.标量子查询 #案例 谁的工资比 Abel 高? -- 查询Abel的工资 #①查询Abel的工资 SELECT salary FROM employees WHERE last_name = 'Abel' #②查询员工的信息,满足 salary>①结果 SELECT * FROM employees WHERE salary>( SELECT salary FROM employees WHERE last_name = 'Abel' ); #2.列子查询(多行子查询)★ 只有一列 但是可以有多行 #案例2:返回其它工种中比job_id为‘IT_PROG’工种任一工资低的 员工的员工号、姓名、job_id 以及salary (10,20,30) #①查询job_id为‘IT_PROG’部门任一工资 SELECT DISTINCT salary FROM employees WHERE job_id = 'IT_PROG' #②查询员工号、姓名、job_id 以及salary,salary<(①)的任意一个 SELECT last_name,employee_id,job_id,salary FROM employees WHERE salary<ANY( SELECT DISTINCT salary FROM employees WHERE job_id = 'IT_PROG' ) AND job_id<>'IT_PROG'; #3、行子查询(结果集一行多列或多行多列) #案例:查询员工编号最小并且工资最高的员工信息 -- 第一种方法 SELECT * FROM employees WHERE (employee_id,salary)=( SELECT MIN(employee_id),MAX(salary) FROM employees ); -- 第二种方法 #①查询最小的员工编号 SELECT MIN(employee_id) FROM employees #②查询最高工资 SELECT MAX(salary) FROM employees #③查询员工信息 SELECT * FROM employees WHERE employee_id=( SELECT MIN(employee_id) FROM employees )AND salary=( SELECT MAX(salary) FROM employees ); #二、select后面 select (里面查询结果 只有一行一列。) /* 仅仅支持标量子查询 */ #案例:查询每个部门的员工个数 SELECT d.*,( SELECT COUNT(*) FROM employees e WHERE e.department_id = d.`department_id` ) 个数 FROM departments d; #三、from后面 /* 将子查询结果充当一张表,要求必须起别名 ... A 2000-4999 ... */ #四、exists后面(相关子查询) /* 语法: exists(完整的查询语句) 结果: 1或0 0 表示 子查询的结果不存在 。 1 表示 子查询的结果存在。 */ -- java 0 1 SELECT EXISTS(SELECT employee_id FROM employees WHERE salary>3000); #案例 查询有员工的部门名 #in SELECT department_name FROM departments d WHERE d.department_id IN( SELECT distinct department_id FROM employees -- 都有员工的部门 。。。 ) ``` ### 9 分页查询 应用场景:实际的web项目中需要根据用户的需求提交对应的分页查询的sql语句 语法: ```mysql select 字段|表达式,... from 表 【where 条件】 【group by 分组字段】 【having 条件】 【order by 排序的字段】 limit 【起始的条目索引,】条目数; ``` 特点: ```mysql 1.起始条目索引从0开始 2.limit子句放在查询语句的最后 3.公式:select * from 表 limit (page-1)*sizePerPage,sizePerPage 假如: 每页显示条目数sizePerPage 要显示的页数 page 示例: #案例1:查询第11条——第25条 SELECT * FROM employees LIMIT 10,15; #案例2:有奖金的员工信息,并且工资较高的前10名显示出来 SELECT * FROM employees WHERE commission_pct IS NOT NULL ORDER BY salary DESC LIMIT 10 ; ``` ### 10 联合查询 **mysql不支持全外连接,但可以通过union实现这样的功能。** 引入:union 联合、合并 语法: ```mysql select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】 select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】 select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】 ..... select 字段|常量|表达式|函数 【from 表】 【where 条件】 ``` 特点: 1、多条查询语句的查询的列数必须是一致的 2、多条查询语句的查询的列的类型几乎相同 3、union代表去重,union all代表不去重 ```mysql #引入的案例:查询部门编号>90或邮箱包含a的员工信息 SELECT * FROM employees WHERE email LIKE '%a%' OR department_id>90;; SELECT * FROM employees WHERE email LIKE '%a%' UNION SELECT * FROM employees WHERE department_id>90; ``` ## DML语言 ### 插入 语法: insert into 表名(字段名,...) values(值1,...); 特点: 1、字段类型和值类型一致或兼容,而且一一对应 2、可以为空的字段,可以不用插入值,或用null填充 3、不可以为空的字段,必须插入值 4、字段个数和值的个数必须一致 5、字段可以省略,但默认所有字段,并且顺序和表中的存储顺序一致 ### 修改 修改单表语法: update 表名 set 字段=新值,字段=新值 【where 条件】 修改多表语法: update 表1 别名1,表2 别名2 set 字段=新值,字段=新值 where 连接条件 and 筛选条件 ### 删除 方式1:delete语句 单表的删除: ★ delete from 表名 【where 筛选条件】 多表的删除: delete 别名1,别名2 from 表1 别名1,表2 别名2 where 连接条件 and 筛选条件; 方式2:truncate语句 truncate table 表名 两种方式的区别【面试题】 ```mysql #1.truncate不能加where条件,而delete可以加where条件 #2.truncate的效率高一丢丢 #3.truncate 删除带自增长的列的表后,如果再插入数据,数据从1开始 #delete 删除带自增长列的表后,如果再插入数据,数据从上一次的断点处开始 #4.truncate删除不能回滚,delete删除可以回滚 ``` ## DDL语句 ### 库和表的管理 #### 库的管理: 一、创建库 create database 库名 二、删除库 drop database 库名 #### 表的管理: ```mysql #1.创建表 create CREATE TABLE IF NOT EXISTS stuinfo( stuId INT, stuName VARCHAR(20), gender CHAR, bornDate DATETIME); ``` ```mysql DESC studentinfo; //查看表结构 desc 表名 #2.修改表 alter 语法:ALTER TABLE 表名 ADD|MODIFY|DROP|CHANGE COLUMN 字段名 【字段类型】; #①修改字段名 ALTER TABLE studentinfo CHANGE COLUMN sex gender CHAR; #②修改表名 ALTER TABLE stuinfo RENAME [TO] studentinfo; #③修改字段类型和列级约束 ALTER TABLE studentinfo MODIFY COLUMN borndate DATE ; #④添加字段 ALTER TABLE studentinfo ADD COLUMN email VARCHAR(20) first; #⑤删除字段 ALTER TABLE studentinfo DROP COLUMN email; ``` ```mysql #3.删除表 DROP TABLE [IF EXISTS] studentinfo; ``` ### 常见数据类型 ```mysql 整型: /* 分类: tinyint、smallint、mediumint、int/integer、bigint 1 2 3 4 8 字节 特点: ① 如果不设置无符号还是有符号,默认是有符号,如果想设置无符号,需要添加unsigned关键字 ② 如果插入的数值超出了整型的范围,会报out of range异常,并且插入临界值 ③ 如果不设置长度,会有默认的长度 长度代表了显示的最大宽度,如果不够会用0在左边填充,但必须搭配zerofill使用! */ 小数: 浮点型 定点型 /* 分类: 1.浮点型 float(M,D) double(M,D) 2.定点型 dec(M,D) decimal(M,D) 特点: 1、 M:整数部位+小数部位 D:小数部位 如果超过范围,则插入临界值 2、 M和D都可以省略 如果是decimal,则M默认为10,D默认为0 如果是float和double,则会根据插入的数值的精度来决定精度 3、 定点型的精确度较高,如果要求插入数值的精度较高如货币运算等则考虑使用 */ 字符型: char varchar 可变字符串 日期型: /* 分类: date只保存日期 time 只保存时间 year只保存年 datetime保存日期+时间 timestamp保存日期+时间 特点: 字节 范围 时区等的影响 datetime 8 1000——9999 不受 timestamp 4 1970-2038 受 */ ``` ### 常见约束 ```mysql NOT NULL -- 非空,用于保证该字段的值不能为空 DEFAULT -- 默认,用于保证该字段有默认值 UNIQUE -- 唯一,用于保证该字段的值具有唯一性,可以为空 CHECK -- 检查约束【mysql中不支持】 PRIMARY KEY -- 主键,用于保证该字段的值具有唯一性,并且非空 FOREIGN KEY -- 外键,用于限制两个表的关系,用于保证该字段的值必须来自于主表的关联列的值 ``` ```mysql #一、创建表时添加约束 #1.添加列级约束 /* 语法: 直接在字段名和类型后面追加 约束类型即可。 只支持:默认、非空、主键、唯一*/ CREATE TABLE major( id INT PRIMARY KEY, majorName VARCHAR(20) ); #查看stuinfo中的所有索引,包括主键、外键、唯一 SHOW INDEX FROM stuinfo; #2.添加表级约束 /* 语法:在各个字段的最下面 【constraint 约束名】 约束类型(字段名) */ #二、修改表时添加约束 /* 1、添加列级约束 alter table 表名 modify column 字段名 字段类型 新约束; 2、添加表级约束 alter table 表名 add 【constraint 约束名】 约束类型(字段名) 【外键的引用】; ``` ### 标识列 ```mysql auto_increment 自动增长 /* 又称为自增长列 含义:可以不用手动的插入值,系统提供默认的序列值 特点: 1、标识列必须和主键搭配吗?不一定,但要求是一个key 2、一个表可以有几个标识列?至多一个! 3、标识列的类型只能是数值型 4、标识列可以通过 SET auto_increment_increment=3;设置步长 可以通过 手动插入值,设置起始值 ``` ### 数据库事务 **事务:现实生活中的一组逻辑操作单元,这组操作要么全部成功,要么全部失败。** 含义:通过一组逻辑操作单元(一组DML——sql语句),将数据从一种状态切换到另外一种状态 特点:(ACID) 原子性:要么都执行,要么都回滚 一致性:保证数据的状态操作前和操作后保持一致 隔离性:多个事务同时操作相同数据库的同一个数据时,一个事务的执行不受另外一个事务的干扰 持久性:一个事务一旦提交,则数据将持久化到本地,除非其他事务对其进行修改 相关步骤: 1、开启事务 2、编写事务的一组逻辑操作单元(多条sql语句) 3、提交事务或回滚事务 #### 事务的分类 隐式事务,没有明显的开启和结束事务的标志 ```mysql 比如 insert、 update、 delete语句本身就是一个事务 ``` 显式事务,具有明显的开启和结束事务的标志 ```mysql 1、开启事务 取消自动提交事务的功能 set autocommit=0; start transaction; 2、编写事务的一组逻辑操作单元(多条sql语句) insert update delete 3、提交事务或回滚事务 commit; -- 提交 rollback; -- 回滚 使用到的关键字 savepoint 断点-- 可以设置一个断点 commit to 断点 rollback to 断点 -- 回滚到断点处,之间的SQL语句无效 ``` #### 事务的隔离级别 事务并发问题如何发生? 当多个事务同时操作同一个数据库的相同数据时 事务的并发问题有哪些? 脏读:一个事务读取到了另外一个事务未提交的数据 不可重复读:同一个事务中,多次读取到的数据不一致 幻读:一个事务读取数据时,另外一个事务进行更新,导致第一个事务读取到了没有更新的数据 如何避免事务的并发问题? 通过设置事务的隔离级别 1、READ UNCOMMITTED 2、READ COMMITTED 可以避免脏读 3、REPEATABLE READ 可以避免脏读、不可重复读和一部分幻读 4、SERIALIZABLE可以避免脏读、不可重复读和幻读 设置隔离级别: ```mysql set session|global transaction isolation level 隔离级别名; ``` 查看隔离级别: ```mysql select @@tx_isolation; ``` ```mysql #演示savepoint 的使用 SET autocommit=0; START TRANSACTION; DELETE FROM account WHERE id=1; SAVEPOINT a;#设置保存点 DELETE FROM account WHERE id=2; ROLLBACK TO a;#回滚到保存点 commit; ``` ### 视图 含义:理解成一张虚拟的表 视图和表的区别: ```mysql 使用方式 占用物理空间 视图 完全相同 不占用,仅仅保存的是sql逻辑 表 完全相同 占用 ``` 视图的好处: 1、sql语句提高重用性,效率高 2、和表实现了分离,提高了安全性 #### 视图的创建 ​ 语法: CREATE VIEW 视图名 AS 查询语句; #### 视图的增删改查 ```mysql -- 视图最好不要做增删改操作 1、查看视图的数据 SELECT * FROM my_v4; SELECT * FROM my_v1 WHERE last_name='Partners'; 2、插入视图的数据 INSERT INTO my_v4(last_name,department_id) VALUES('虚竹',90); 3、修改视图的数据 UPDATE my_v4 SET last_name ='梦姑' WHERE last_name='虚竹'; 4、删除视图的数据 DELETE FROM my_v4; ``` #### 某些视图不能更新 ​ 包含以下关键字的sql语句:分组函数、distinct、group by、having、union或者union all 常量视图 Select中包含子查询 join from一个不能更新的视图 where子句的子查询引用了from子句中的表 #### 视图逻辑的更新 ```mysql #方式一: create or replace CREATE OR REPLACE VIEW test_v7 AS SELECT last_name FROM employees WHERE employee_id>100; #方式二: alter ALTER VIEW test_v7 AS SELECT employee_id FROM employees; SELECT * FROM test_v7; ``` #### 视图的删除 ```mysql DROP VIEW test_v1,test_v2,test_v3; ``` #### 视图结构的查看 ```mysql DESC test_v7; SHOW CREATE VIEW test_v7; ``` ### 存储过程 含义:一组经过预先编译的sql语句的集合 ```mysql -- 好处: 1、提高了sql语句的重用性,减少了开发程序员的压力 2、提高了效率 3、减少了传输次数 4、安全性 -- 缺点 1、调试困难 -- mysql中不支持调试 2、CPU、内存耗费大 3、维护与开发困难 ``` 分类: ```mysql 1、无返回无参 2、仅仅带in类型,无返回有参 3、仅仅带out类型,有返回无参 4、既带in又带out,有返回有参 5、带inout,有返回有参 注意:in、out、inout都可以在一个存储过程中带多个 ``` #### 创建存储过程 语法: ```mysql create procedure 存储过程名(in|out|inout 参数名 参数类型,...) begin 存储过程体 end ``` 类似于方法: ```mysql 修饰符 返回类型 方法名(参数类型 参数名,...){ 方法体; } ``` ```mysql -- 注意 1、需要设置新的结束标记 delimiter 新的结束标记 示例: delimiter $ CREATE PROCEDURE 存储过程名(IN|OUT|INOUT 参数名 参数类型,...) BEGIN sql语句1; sql语句2; END $ 2、存储过程体中可以有多条sql语句,如果仅仅一条sql语句,则可以省略begin end 3、参数前面的符号的意思 in:该参数只能作为输入 (该参数不能做返回值) out:该参数只能作为输出(该参数只能做返回值) inout:既能做输入又能做输出 ``` ##### 调用存储过程 ```mysql call 存储过程名(实参列表) #案例1:根据输入的女神名,返回对应的男神名和魅力值 CREATE PROCEDURE myp7(IN beautyName VARCHAR(20),OUT boyName VARCHAR(20),OUT usercp INT) BEGIN SELECT boys.boyname ,boys.usercp INTO boyname,usercp FROM boys RIGHT JOIN beauty b ON b.boyfriend_id = boys.id WHERE b.name=beautyName ; END -- 又返回参数时,需要设置变量代替返回参数,然后查询变量即可得到返回的值 #调用 CALL myp7('小昭',@name,@cp) SELECT @name,@cp #案例2 :创建存储过程实现,用户是否登录成功 CREATE PROCEDURE myp4(IN username VARCHAR(20),IN PASSWORD VARCHAR(20)) BEGIN DECLARE result INT DEFAULT 0;#声明并初始化 -- 局部变量 SELECT COUNT(*) INTO result#赋值 FROM admin WHERE admin.username = username AND admin.password = PASSWORD; SELECT IF(result>0,'成功','失败');#使用 END #调用 CALL myp3('张飞','8888') ``` ```mysql #删除存储过程 #语法:drop procedure 存储过程名 DROP PROCEDURE p1; DROP PROCEDURE p2,p3;#× -- 不行 #查看存储过程的信息 DESC myp2;× -- 不行 SHOW CREATE PROCEDURE myp2; ``` ### 函数 #### 创建函数 学过的函数:LENGTH、SUBSTR、CONCAT等 语法: ```mysql CREATE FUNCTION 函数名(参数名 参数类型,...) RETURNS 返回类型 BEGIN 函数体 END #调用函数 SELECT 函数名(实参列表) ``` #### 函数和存储过程的区别 关键字 调用语法 返回值 应用场景 函数 FUNCTION SELECT 函数() 只能是一个 一般用于查询结果为一个值并返回时,当有返回值而且仅仅一个 存储过程 PROCEDURE CALL 存储过程() 可以有0个或多个 一般用于更新 ```mysql #查看函数 SHOW CREATE FUNCTION myf3; #删除函数 DROP FUNCTION myf3; #案例 #创建函数,实现传入两个float,返回二者之和 CREATE FUNCTION test_fun1(num1 FLOAT,num2 FLOAT) RETURNS FLOAT BEGIN DECLARE SUM FLOAT DEFAULT 0; SET SUM=num1+num2; RETURN SUM; END SELECT test_fun1(1,2) ``` ### 变量 #### 系统变量 ##### 1、全局变量 作用域:针对于所有会话(连接)有效,但不能跨重启 ```mysql 查看所有全局变量 SHOW GLOBAL VARIABLES; 查看满足条件的部分系统变量 SHOW GLOBAL VARIABLES LIKE '%char%'; 查看指定的系统变量的值 SELECT @@global.autocommit; 为某个系统变量赋值 SET @@global.autocommit=0; SET GLOBAL autocommit=0; ``` ##### 2、会话变量 作用域:针对于当前会话(连接)有效 ```mysql 查看所有会话变量 SHOW SESSION VARIABLES; 查看满足条件的部分会话变量 SHOW SESSION VARIABLES LIKE '%char%'; 查看指定的会话变量的值 SELECT @@autocommit; SELECT @@session.tx_isolation; 为某个会话变量赋值 SET @@session.tx_isolation='read-uncommitted'; SET SESSION tx_isolation='read-committed'; ``` #### 自定义变量 ##### 1、用户变量 声明并初始化: ```mysql SET @变量名=值; SET @变量名:=值; SELECT @变量名:=值; ``` 赋值: ```mysql 方式一:一般用于赋简单的值 SET 变量名=值; SET 变量名:=值; SELECT 变量名:=值; 方式二:一般用于赋表 中的字段值 SELECT 字段名或表达式 INTO 变量 FROM 表; 使用: select @变量名; ``` ##### 2、局部变量 声明: ```mysql declare 变量名 类型 【default 值】; ``` 赋值: ```mysql -- 方式一:一般用于赋简单的值 SET 变量名=值; SET 变量名:=值; SELECT 变量名:=值; -- 方式二:一般用于赋表 中的字段值 SELECT 字段名或表达式 INTO 变量 FROM 表; -- 使用: select 变量名 ``` 二者的区别: ```mysql 作用域 定义位置 语法 用户变量 当前会话 会话的任何地方 加@符号,不用指定类型 局部变量 定义它的BEGIN END中 BEGIN END的第一句话 一般不用加@,需要指定类型 #案例:声明两个变量,求和并打印 #用户变量 SET @m=1; SET @n=1; SET @sum=@m+@n; SELECT @sum; #局部变量 DECLARE m INT DEFAULT 1; DECLARE n INT DEFAULT 1; DECLARE SUM INT; SET SUM=m+n; SELECT SUM; ``` ### 流程控制结构 #### 分支 ##### 1、if函数 ​ 语法:if(条件,值1,值2) 特点:可以用在任何位置 ##### 2、case语句 ```mysql 语法: 情况一:类似于switch case 表达式 when 值1 then 结果1或语句1(如果是语句,需要加分号) when 值2 then 结果2或语句2(如果是语句,需要加分号) ... else 结果n或语句n(如果是语句,需要加分号) end 【case】(如果是放在begin end中需要加上case,如果放在select后面不需要) 情况二:类似于多重if case when 条件1 then 结果1或语句1(如果是语句,需要加分号) when 条件2 then 结果2或语句2(如果是语句,需要加分号) ... else 结果n或语句n(如果是语句,需要加分号) end 【case】(如果是放在begin end中需要加上case,如果放在select后面不需要) 特点: 可以用在任何位置 #案例:创建函数,实现传入成绩,如果成绩>90,返回A,如果成绩>80,返回B,如果成绩>60,返回C,否则返回D CREATE FUNCTION test_if(score FLOAT) RETURNS CHAR BEGIN DECLARE ch CHAR DEFAULT 'A'; IF score>90 THEN SET ch='A'; ELSEIF score>80 THEN SET ch='B'; ELSEIF score>60 THEN SET ch='C'; ELSE SET ch='D'; END IF; RETURN ch; END SELECT test_if(87) ``` ##### 3、if elseif语句 ```mysql 语法: if 情况1 then 语句1; elseif 情况2 then 语句2; ... else 语句n; end if; 特点: 只能用在begin end中!!! ``` 三者比较: 应用场合 if函数 简单双分支 case结构 等值判断 的多分支 if结构 区间判断 的多分支 #### 循环 ```mysql /* 分类: while、loop、repeat 循环控制: iterate类似于 continue,继续,结束本次循环,继续下一次 leave 类似于 break,跳出,结束当前所在的循环 */ #1.while 语法: 【标签:】while 循环条件 do 循环体; end while【 标签】; 联想: while(循环条件){ 循环体; } #2.loop 语法: 【标签:】loop 循环体; end loop 【标签】; 可以用来模拟简单的死循环 #3.repeat 语法: 【标签:】repeat 循环体; until 结束循环的条件 end repeat 【标签】; ``` ```mysql 语法: 【标签:】WHILE 循环条件 DO 循环体 END WHILE 【标签】; #案例:批量插入,根据次数插入到admin表中多条记录,如果次数>20则停止 TRUNCATE TABLE admin$ DROP PROCEDURE test_while1$ CREATE PROCEDURE test_while1(IN insertCount INT) BEGIN DECLARE i INT DEFAULT 1; a:WHILE i<=insertCount DO INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000'); IF i>=20 THEN LEAVE a; END IF; SET i=i+1; END WHILE a; END CALL test_while1(100) #添加iterate语句 #案例:批量插入,根据次数插入到admin表中多条记录,只插入偶数次 TRUNCATE TABLE admin DROP PROCEDURE test_while1 CREATE PROCEDURE test_while1(IN insertCount INT) BEGIN DECLARE i INT DEFAULT 0; a:WHILE i<=insertCount DO SET i=i+1; IF MOD(i,2)!=0 THEN ITERATE a; END IF; INSERT INTO admin(username,`password`) VALUES(CONCAT('xiaohua',i),'0000'); END WHILE a; END CALL test_while1(100) ``` 特点: ```mysql 只能放在BEGIN END里面 如果要搭配leave跳转语句,需要使用标签,否则可以不用标签 leave类似于java中的break语句,跳出所在循环!!! ```