当前位置:   article > 正文

SQL学习(基础)_sql语句创建用户名user_rose,登录名为rose_lib

sql语句创建用户名user_rose,登录名为rose_lib

目录

(二)、DQL语言 

1. 基础查询

 2. 条件查询

3. 排序函数

4. 常见函数的学习

单行函数

 分组函数

5. 分组查询

6. 连接查询

7. 子查询

8. 分页查询

9. 联合查询(尚硅谷-124节)

(三)、DML语言

 3.1 插入语句

 3.2 修改语句

3.3 删除语句 

(四)、DDL语言

4.1 数据定义语言——对库和表的管理

4.1.1 库的管理

4.1.2 表的管理

4.2 数据类型

4.3 常见约束

(五)、TCL语言

(六)、其他 

6.1 视图

6.2 变量

6.3 存储过程和函数

6.4 流程控制结构


(二)、DQL语言 

  1. # 交叉连接
  2. - 语法:
  3. select 查询列表
  4. from1 别名
  5. cross join2 别名;
  6. - 特点:
  7. 类似于笛卡尔乘积:所有行数据两两连接

1. 基础查询

  1. # 1、查询单个字段
  2. select 字段名 from 表名;
  3. # 2、查询多个字段
  4. select 字段名,字段名 from 表名;
  5. # 3、查询所有字段
  6. select * from 表名;
  7. # 4、查询常量
  8. # 注意:字符型和日期型的常量值必须用单引号引起来,数值型不需要
  9. select 常量值;
  10. # 5、查询函数
  11. select 函数名(实参列表);
  12. # 6、查询表达式
  13. select 100/1234;
  14. # 7、起别名
  15. # ① as
  16. # ② 空格
  17. # 8、去重
  18. select distinct 字段名 from 表名;
  19. # 9+
  20. # 作用:做加法运算
  21. select 数值+数值; # 直接运算
  22. select 字符+数值; # 先试图将字符转换成数值,如果转换成功,则继续运算;否则转换成0,再做运算
  23. select null+值; # 结果都为null
  24. # 10、【补充】concat函数
  25. # 功能:拼接字符
  26. select concat(字符1,字符2,字符3,...);
  27. # 11、【补充】ifnull函数
  28. # 功能:判断某字段或表达式是否为null,如果为null 返回指定的值,否则返回原本的值
  29. select ifnull(commission_pct,0) from employees;
  30. # 12、【补充】isnull函数
  31. # 功能:判断某字段或表达式是否为null,如果是,则返回1,否则返回0

 2. 条件查询

  1. # 1.条件查询的基本结构
  2. select 查询列表 from 表名 where 筛选条件
  3. # 2.简单条件运算符
  4. > < = <> != >= <=
  5. <=>安全等于 # 可以判断null
  6. # 3. 逻辑运算符
  7. && and
  8. || or
  9. ! not
  10. # 4、模糊查询
  11. between and # 左右边界不能颠倒顺序
  12. between 120 and 100 # 等价于 >= 120 && <= 100
  13. in ('', '') # in列表值类型必须统一,且不支持通配符
  14. is null /is not null # 只用于判断null值; =不能判断null
  15. like # 一般搭配通配符使用,可以判断字符型或数值型 ;不能判断null
  16. # 5.通配符:
  17. %:任意多个字符
  18. _:任意单个字符
  19. 通配符转义 \ 或者 '_$_' ESCAPE '$'
  20. 普通类型的数值 null值 可读性
  21. is null × √ √
  22. <=> √ √ ×

1. 两个查询语句的执行结果是否相同? 

  1. select * from employees;
  2. select * from employees where name like '%%' and id like '%%';
  3. #解:不一样,若name或者id有null值则查不出来
  4. select * from employees;
  5. select * from employees where commission_pct like '%%' or last_name id like '%%' or employee_id like '%%';
  6. #解:一样,总归有一个条件不含null

 2. 查询员工号为176的员工的姓名和部门号和年薪

  1. SELECT
  2. last_name,
  3. department_id,
  4. salary*12*(1+IFNULL(commission_pct,0)) AS 年薪
  5. FROM
  6. employees;

3. 查询employees表中,job_id不为“IT” 或者 工资为12000的员工信息

  1. SELECT *
  2. FROM employees
  3. WHERE job_id <> 'IT' # 或者 WHERE NOT job_id = 'IT'
  4. OR salary=12000;

3. 排序函数

  1. # 1. 排序查询的基本结构
  2. select 查询列表
  3. from
  4. where 筛选条件
  5. order by 排序列表 [asc}desc]
  6. # 2. 特点
  7. /*
  8. 1、asc :升序,如果不写默认升序
  9. desc:降序
  10. 2、排序列表 支持 单个字段、多个字段、函数、表达式、别名
  11. 3、order by的位置一般放在查询语句的最后(除limit语句之外)
  12. */

 1. 查询员工信息,要求先按员工工资升序,再按员工编号降序【按多个字段排序】

  1. SELECT *
  2. FROM employees
  3. ORDER BY salary ASC,employee_id DESC;

2. 查询邮箱中包含e的员工信息,并按邮箱的字节数降序,再按部门号升序

  1. SELECT *,LENGTH(email)
  2. FROM employees
  3. WHERE email LIKE '%e%'
  4. ORDER BY LENGTH(email) DESC,department_id ASC;

4. 常见函数的学习

  • 功能:类似于java、python中的方法,
  • 好处:提高代码重用性和隐藏实现细节
  • 调用:select 函数名(实参列表) 【from 表】;

单行函数

  1. # 1、字符函数 参数为字符串类型
  2. # concat:连接
  3. # ifnull:判断是否为null,如果为null,则替换为...
  4. # substr:截取子串,索引从1开始,截取某个值后边的信息
  5. # upper:变大写
  6. # lower:变小写
  7. # replace:替换:把字符串中的x1全部替换为X2
  8. # length:获取字节长度
  9. # trim:去前后空格,或者前后某个字段
  10. # lpad:左填充:用指定的字符实现左填充指定长度
  11. # rpad:右填充
  12. # instr:获取子串第一次出现的索引,如果找不到返回0
  13. SELECT LENGTH('john');
  14. SELECT CONCAT(last_name,'_',first_name) 姓名 FROM employees;
  15. SELECT UPPER('john');
  16. SELECT LOWER('joHn');
  17. SELECT CONCAT(UPPER(last_name),LOWER(first_name)) 姓名
  18. FROM employees;
  19. SELECT SUBSTR('李莫愁爱上了陆展元',7) out_put;
  20. --截取索引7后边的所有字符:陆展元
  21. SELECT SUBSTR('李莫愁爱上了陆展元',1,3) out_put;
  22. --截取指定索引处指定长度的字符:李莫愁
  23. SELECT CONCAT(UPPER(SUBSTR(last_name,1,1)),'_',LOWER(SUBSTR(last_name,2))) out_put
  24. --姓名中的首字符大写,其他字符小写然后用_拼接,显示出来
  25. FROM employees;
  26. SELECT INSTR('杨不殷六侠悔爱上了殷六侠','殷八侠') AS out_put;
  27. SELECT LENGTH(TRIM(' 张翠山 ')) AS out_put;
  28. SELECT TRIM('aa' FROM 'aaaaaa张aaaa翠山aaaaa') AS out_put;
  29. --去掉前后的aa,得到张aaaa翠山a
  30. SELECT LPAD('殷素素',2,'*') AS out_put;
  31. --素素
  32. SELECT RPAD('殷素素',12,'ab') AS out_put;
  33. --殷素素ababababa
  34. SELECT REPLACE('周芷若周芷若张无忌爱上了周芷若','周芷若','赵敏') AS out_put;
  35. # 2、数学函数
  36. # ceil:向上取整
  37. # round:四舍五入
  38. # mod(a,b):a/b 后取余
  39. # floor:向下取整
  40. # truncate:截断,保留n位小数
  41. # rand:获取随机数,返回0-1之间的小数
  42. SELECT ROUND(-1.55);
  43. SELECT ROUND(1.567,2);
  44. SELECT CEIL(-1.02);
  45. SELECT FLOOR(-9.99);
  46. SELECT TRUNCATE(1.69999,1);
  47. #mod取余
  48. /*
  49. mod(a,b) : a-a/b*b
  50. mod(-10,-3):-10- (-10)/(-3)*(-3)=-1
  51. */
  52. SELECT MOD(10,-3);
  53. SELECT 10%3;
  54. # 3、日期函数
  55. # now:返回当前日期+时间
  56. # year(日期参数):返回日期参数中的年
  57. # month:返回月
  58. # day:返回日
  59. # date_format:将日期转换成字符
  60. # curdate:返回当前日期,不包含时间
  61. # str_to_date:将字符通过指定的格式转换成日期
  62. # curtime:返回当前时间
  63. # hour:小时
  64. # minute:分钟
  65. # second:秒
  66. # datediff:返回两个日期相差的天数
  67. # monthname:以英文形式返回月
  68. SELECT NOW();
  69. SELECT CURDATE();
  70. SELECT CURTIME();
  71. SELECT YEAR(NOW()) 年;
  72. SELECT YEAR('1998-1-1') 年;
  73. SELECT YEAR(hiredate) 年 FROM employees;
  74. SELECT MONTH(NOW()) 月;
  75. SELECT MONTHNAME(NOW()) 月;
  76. SELECT STR_TO_DATE('1998-3-2','%Y-%c-%d') AS out_put;
  77. #查询入职日期为1992--4-3的员工信息
  78. SELECT * FROM employees WHERE hiredate = '1992-4-3';
  79. SELECT * FROM employees WHERE hiredate = STR_TO_DATE('4-3 1992','%c-%d %Y');
  80. -- %c是1,2,3月份;%m是01,02,03月份。 %Y是4位年份,%y是两位年份。 %H是24小时制。
  81. SELECT DATE_FORMAT(NOW(),'%y年%m月%d日') AS out_put;
  82. #查询有奖金的员工名和入职日期(xx月/xx日 xx年)
  83. SELECT last_name,DATE_FORMAT(hiredate,'%m月/%d日 %y年') 入职日期
  84. FROM employees
  85. WHERE commission_pct IS NOT NULL;
  86. # 4、其他函数
  87. # version 当前数据库服务器的版本
  88. # database 当前打开的数据库
  89. # user当前用户
  90. # password('字符'):返回该字符的密码形式
  91. # md5('字符'):返回该字符的md5加密形式
  92. SELECT VERSION();
  93. SELECT DATABASE();
  94. SELECT USER();
  95. #5、流程控制函数
  96. /*
  97. ①if(条件表达式,表达式1,表达式2):如果条件表达式成立,返回表达式1,否则返回表达式2
  98. */
  99. SELECT IF(10<5,'大','小');
  100. SELECT last_name,commission_pct,IF(commission IS NULL,"没奖金,呵呵","有奖金,嘻嘻") 备注
  101. FROM employees;
  102. /*
  103. ②case情况1 放在SELECT后,作为一个新的属性显示
  104. case 要判断的变量或表达式或字段
  105. when 常量1 then 要显示的值1;
  106. when 常量2 then 要显示的值2;
  107. ...
  108. else 要显示的值n;
  109. end
  110. */
  111. SELECT salary 原始工资,department_id,
  112. CASE department_id
  113. WHEN 30 THEN salary*1.1
  114. WHEN 40 THEN salary*1.2
  115. WHEN 50 THEN salary*1.3
  116. ELSE salary
  117. END AS 新工资
  118. FROM employees;
  119. /*
  120. ③case情况2 多重if
  121. case
  122. when 条件1 then 值1 【或语句1;】
  123. when 条件2 then 值2 【或语句2;】
  124. ...
  125. else 值n
  126. end
  127. */
  128. SELECT salary,
  129. CASE
  130. WHEN salary>20000 THEN 'A'
  131. WHEN salary>15000 THEN 'B'
  132. WHEN salary>10000 THEN 'C'
  133. ELSE 'D'
  134. END AS 工资级别
  135. FROM employees;

1. 显示系统时间(注:日期+时间)

SELECT NOW()

2. 查询员工号,姓名,工资,以及工资提高百分之20后的结果

  1. SELECT employee_id,last_name,salary,salary*1.2 "new salary"
  2. FROM employees;

3. 将员工的姓名按首字母排序,并写出姓名的长度(Length )

  1. SELECT last_name,LENGTH(last_name) 长度,SUBSTR(last_name,1,1) 首字符
  2. FROM employees
  3. ORDER BY 首字符 ASC;
  4. --按last_name排序的话,如果首字母一样,则按第二个字母再排序
  5. ORDER BY last_name ASC;

4. 做一个查询,产生效果:<last_name> earns <salary> monthly but wants <salary*3>

  1. SELECT CONCAT(last_name,'earns',salary,'monthly but wants',salary*3) AS Dream Salary
  2. FROM employees
  3. WHERE salary=24000;

5. 要求使用case-when实现下面的条件

  1. SELECT job_id AS job,
  2. CASE job_id
  3. WHEN AD_PRES THEN A
  4. WHEN ST_MAN THEN B
  5. WHEN IT_PROG THEN C
  6. --else D
  7. END AS 等级
  8. FROM employees;

 分组函数

  1. /*
  2. 功能:用作统计使用,又称为聚合函数或统计函数或组函数
  3. 分类:
  4. sum 求和、avg 平均值、max 最大值 、min 最小值 、count 计算个数
  5. 特点:
  6. 1、sum、avg一般用于处理数值型
  7. max、min、count可以处理任何类型
  8. 2、以上分组函数都忽略null值
  9. 3、可以和distinct搭配实现去重的运算
  10. 4、count函数的单独介绍
  11. 一般使用count(*)用作统计行数
  12. 5、和分组函数一同查询的字段要求是group by后的字段,其它的都不行
  13. */
  14. #1、简单 的使用
  15. SELECT SUM(salary) FROM employees;
  16. SELECT AVG(salary) FROM employees;
  17. SELECT MIN(salary) FROM employees;
  18. SELECT MAX(salary) FROM employees;
  19. SELECT COUNT(salary) FROM employees;
  20. SELECT SUM(salary) 和,AVG(salary) 平均,MAX(salary) 最高,MIN(salary) 最低,COUNT(salary) 个数
  21. FROM employees;
  22. SELECT SUM(salary) 和,ROUND(AVG(salary),2) 平均,MAX(salary) 最高,MIN(salary) 最低,COUNT(salary) 个数
  23. FROM employees;
  24. #2、参数支持哪些类型:数值型,
  25. SELECT SUM(last_name) ,AVG(last_name) FROM employees; --错
  26. SELECT SUM(hiredate) ,AVG(hiredate) FROM employees; --错
  27. SELECT MAX(last_name),MIN(last_name) FROM employees; --对,因为last_name可以按字母排序,所以有最值
  28. SELECT MAX(hiredate),MIN(hiredate) FROM employees; --对
  29. SELECT COUNT(commission_pct) FROM employees; --对
  30. SELECT COUNT(last_name) FROM employees; --任何类型都支持:计算非空值得个数
  31. #3、是否忽略null
  32. SELECT SUM(commission_pct) ,AVG(commission_pct),SUM(commission_pct)/35,SUM(commission_pct)/107 FROM employees; --null没有参与运算
  33. SELECT MAX(commission_pct) ,MIN(commission_pct) FROM employees; --忽略null
  34. SELECT COUNT(commission_pct) FROM employees; --忽略null
  35. #4、和distinct搭配,实现去重运算
  36. SELECT SUM(DISTINCT salary), SUM(salary) FROM employees;
  37. SELECT COUNT(DISTINCT salary), COUNT(salary) FROM employees; --一样工资得去掉
  38. #5、count函数的详细介绍
  39. SELECT COUNT(salary) FROM employees; --所有salary这一列中非null字段
  40. SELECT COUNT(*) FROM employees; --统计非null行数
  41. SELECT COUNT(1) FROM employees; --相当于在原表中加了一列相同行数的1,统计1的个数
  42. 效率:
  43. MYISAM存储引擎下 ,COUNT(*)的效率高
  44. INNODB存储引擎下,COUNT(*)和COUNT(1)的效率差不多,比COUNT(字段)要高一些
  45. #6、和分组函数一同查询的字段有限制
  46. SELECT AVG(salary),employee_id FROM employees; --没有意义,不是一个规则的表格

1. 查询公司员工工资的最大值,最小值,平均值,总和

  1. SELECT MAX(salary) mx_sal ,MIN(salary) mi_sal ,ROUND(AVG(salary),2) ag_sal,SUM(salary) su_sal
  2. FROM employees;

2. 查询员工表中的最大入职时间和最小入职时间的相差天数

  1. --MAX(hiredate)和MIN(hiredate)都是时间,如何求相差天数? 函数DATEDIFF
  2. SELECT DATEDIFF(MAX(hiredate),DATEDIFF(MIN(hiredate)))
  3. SELECT DATEDIFF('2017-10-1','2017-9-29');

3. 查询员工部门编号为90的员工个数

  1. SELECT count(*)
  2. FROM employees
  3. WHERE department_id = 90;

5. 分组查询

  1. /*
  2. 语法:
  3. select column,group_function(column)
  4. from 表
  5. [where 筛选条件]
  6. group by 分组的字段
  7. [order by 排序的字段];
  8. 特点:
  9. 1、和分组函数一同查询的字段必须是group by后出现的字段
  10. 2、分组查询中的筛选分为两类:分组前筛选和分组后筛选
  11. 数据源 位置 关键字
  12. 分组前筛选 原始表 group by前 where
  13. 分组后筛选 group by后的结果集 g_b后 having
  14. (1)问题1:分组函数做筛选能不能放在where后面
  15. 答:不能。分组函数做条件肯定放在HAVING子句中
  16. (2)问题2:where——group by——having
  17. 一般来讲,能用分组前筛选的,尽量使用分组前筛选,提高效率
  18. 3、分组可以按单个字段也可以按多个字段
  19. 4、可以搭配着排序使用,后面加order by
  20. */
  21. #引入:查询每个部门的员工个数
  22. SELECT COUNT(*) FROM employees GROUP BY department_id;
  23. #1.简单的分组
  24. #案例1:查询每个工种的员工平均工资
  25. SELECT AVG(salary),job_id
  26. FROM employees
  27. GROUP BY job_id;
  28. #案例2:查询每个位置的部门个数
  29. SELECT COUNT(*),location_id
  30. FROM departments
  31. GROUP BY location_id;
  32. #2、可以实现分组前的筛选
  33. #案例1:查询邮箱中包含a字符的 每个部门的最高工资
  34. SELECT MAX(salary),department_id
  35. FROM employees
  36. WHERE email LIKE '%a%'
  37. GROUP BY department_id;
  38. #案例2:查询有奖金的每个领导手下员工的平均工资
  39. SELECT AVG(salary),manager_id
  40. FROM employees
  41. WHERE commission_pct IS NOT NULL
  42. GROUP BY manager_id;
  43. #3、分组后筛选
  44. #案例1:查询哪个部门的员工个数>5
  45. #①查询每个部门的员工个数
  46. SELECT COUNT(*),department_id
  47. FROM employees
  48. GROUP BY department_id;
  49. #② 筛选刚才①结果,查询那个部门的员工数>5:需要使用 HAVING
  50. SELECT COUNT(*),department_id
  51. FROM employees
  52. GROUP BY department_id
  53. HAVING COUNT(*)>5;
  54. #案例2:每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
  55. SELECT job_id,MAX(salary)
  56. FROM employees
  57. WHERE commission_pct IS NOT NULL
  58. GROUP BY job_id
  59. HAVING MAX(salary)>12000;
  60. #案例3:领导编号>102的每个领导手下的最低工资大于5000的领导编号和最低工资
  61. manager_id>102
  62. SELECT manager_id,MIN(salary)
  63. FROM employees
  64. GROUP BY manager_id
  65. HAVING MIN(salary)>5000;
  66. #4.添加排序
  67. #案例:每个工种有奖金的员工的最高工资>6000的工种编号和最高工资,按最高工资升序
  68. SELECT job_id,MAX(salary) m
  69. FROM employees
  70. WHERE commission_pct IS NOT NULL
  71. GROUP BY job_id
  72. HAVING m>6000
  73. ORDER BY m ;
  74. #5.按多个字段分组,且可以配合排序使用
  75. #案例:查询每个工种每个部门的最低工资,并按最低工资降序
  76. SELECT MIN(salary),job_id,department_id
  77. FROM employees
  78. GROUP BY department_id,job_id --顺序不影响
  79. ORDER BY MIN(salary) DESC;
  1. #1.查询各job_id的员工工资的最大值、最小值、平均值、总和,并按job_id升序排序
  2. SELECT MAX(salary),MIN(salary),AVG(salary),SUM(salary),job_id
  3. FROM employees
  4. GROUP BY job_id
  5. ORDER BY job_id ASC;
  6. #2.查询最低工资和最高工资的差距(DIFFERENCE)
  7. SELECT MAX(salary)-MIN(salary) AS DIFFERENCE
  8. FROM employees;
  9. #3.查询各个管理者手下员工的最低工资,其中最低工资不能低于6000,没有管理员工的不能计算在内
  10. SELECT MIN(salary),manager_id
  11. FROM employees
  12. WHERE manager_id IS NOT NULL
  13. GROUP BY manager_id
  14. HAVING MIN(salary)>=6000;
  15. #4.查询所有部门的编号,员工数量和工资平均值,并按平均工资排序
  16. SELECT department_id,COUNT(*),AVG(salary) AS a
  17. FROM employees
  18. GROUP BY department_id
  19. ORDER BY a DESC;
  20. #5.选择具有各个job_id的员工人数
  21. SELECT job_id, COUNT(*) 个数
  22. FROM employees
  23. GROUP BY job_id;

6. 连接查询

  1. # 1.连接查询的含义:又称多表查询,当查询的字段来自于多个表时,就会用到连接查询
  2. SELECT name,boy_name FROM beauty,boys;
  3. 笛卡尔乘积现象:表1 有m行,表2有n行,结果=m*n行
  4. 发生原因:没有有效的连接条件
  5. 如何避免:添加有效的连接条件
  6. # 2.分类:
  7. # 按年代分类:
  8. sql92标准:仅仅支持内连接
  9. sql99标准【推荐】:支持内连接+外连接(左外和右外)+交叉连接
  10. # 按功能分类:
  11. 内连接:
  12. 等值连接
  13. 非等值连接
  14. 自连接
  15. 外连接:
  16. 左外连接
  17. 右外连接
  18. 全外连接
  19. 交叉连接
  20. # 3. SQL92语法
  21. # 等值连接
  22. select 查询列表
  23. from1 别名,表2 别名
  24. where1.key=2.key
  25. and 筛选条件】
  26. and 筛选条件2
  27. group by 分组字段】
  28. having 分组后的筛选】
  29. order by 排序字段】
  30. ① 一般为表起别名
  31. ② 多表的顺序可以调换
  32. ③ n表连接至少需要n-1个连接条件
  33. ④ 等值连接的结果是多表的交集部分
  34. #案例1:查询女神名对应的男神名
  35. SELECT name, boyname
  36. FROM beauty, boys
  37. WHERE beauty. boyfriend_id = boys.id;
  38. #案例2:查询员工名和对应的部门名
  39. SELECT last_name, department_id
  40. FROM employees, departments
  41. WHERE employees.'department_id'=departments.'department_id';
  42. #案例3:查询员工名,工种号,工种名
  43. SELECT last_name, employees.job_id,job_title --必须限定是employees.job_id还是jobs.job_id
  44. FROM employees,jobs
  45. WHERE employees.job_id = jobs.job_id;
  46. --此时也可以不限定job_id,为表起别名
  47. SELECT e.last_name, e.job_id,j.job_title --必须使用别名,有别名之后,查询字段不能用原来的名
  48. FROM employees AS e,jobs AS j
  49. WHERE e.job_id = j.job_id;
  50. #可以加筛选?
  51. #案例1:查询有奖金的员工名、部门名
  52. SELECT last_name, department_name
  53. FROM employees e, departments d
  54. WHERE e.department_id=d.department_id
  55. AND e.commission_pct IS NOT NULL;
  56. #案例2:查询城市名中第二个字符为o的部门名和城市名
  57. SELECT department_name, city
  58. FROM departments d, locations l
  59. WHERE d.location_id = l.location_id
  60. AND city LIKE "_o%";
  61. #可以加分组?
  62. #案例1:查询每个城市的部门个数
  63. SELECT COUNT(*) 个数, city
  64. FROM departments d, locations l
  65. WHERE d.location_id = l.location_id
  66. GROUP BY l.city;
  67. #案例2:查询有奖金的每个部门的部门名和部门领导编号和该部门的最低工资
  68. SELECT department_name,d.manager_id,MIN(salary)
  69. FROM departments d, employees e
  70. WHERE d.department_id = e.department_id
  71. AND commission_pct IS NOT NULL
  72. GROUP BY d.department_id, d.manager_id; --不确定manager_id和department_id是否一一对应,所以将这两个都作为分组条件。
  73. #可不可以加排序?
  74. #案例1:查询每个工种的工种名和员工的个数,并且按员工个数排序
  75. SELECT job_title, COUNT(*)
  76. FROM jobs j, employees e
  77. WHERE j.job_id=e.job_id
  78. GROUP BY job_title
  79. ORDER BY COUNT(*) DESC;
  80. #是否可以实现三表连接?
  81. #查询员工名、部门名和所在城市
  82. SELECT last_name,department_name,city
  83. FROM employees e, departments d, locations l
  84. WHERE e.department_id = d.department_id
  85. AND d.location_id= l.location_id;
  86. --再加AND city LIKE "s%"; 也可以再加筛选分组排序
  87. # 非等值连接
  88. select 查询列表
  89. from1 别名,表2 别名
  90. where 非等值的连接条件
  91. and 筛选条件】
  92. group by 分组字段】
  93. having 分组后的筛选】
  94. order by 排序字段】
  95. #案例1:查询员工的工资和工资级别
  96. SELECT salary,grade_level
  97. FROM employees e, job_grades g
  98. WHERE salary BETWEEN g.lowest_sal AND g.highest_sal;
  99. --再加一个筛选 AND g.grade_level="A";
  100. # 自连接:相当于等值连接,但是是自己连接自己
  101. select 查询列表
  102. from 表 别名1,表 别名2
  103. where 等值的连接条件
  104. and 筛选条件】
  105. group by 分组字段】
  106. having 分组后的筛选】
  107. order by 排序字段】
  108. #案例1:查询员工名和上级的名称(查某个员工的领导编号,再根据领导编号在员工表里查编号)
  109. SELECT e.employee_id , e.last_name, m.employee_id, m.last_name --员工id,员工名,领导id,领导名
  110. FROM employees e, employees m --e是员工表,m是领导表
  111. WHERE e.manager_id=m.employee_id;
  1. #1.显示员工表的最大工资、平均工资
  2. SELECT MAX(salary),AVG(salary)
  3. FROM employees;
  4. #2.查询员工表的employee_id,job_id,last_name,按department_id降序,salary升序
  5. SELECT employee_id,job_id,last_name
  6. FROM employees
  7. ORDER BY department_id DESC,salary ASC;
  8. #3.查询员工表的job_id中包含a和e的,并且a在e前面
  9. SELECT job_id
  10. FROM employees
  11. WHERE job_id LIKE "%a%e%";
  12. #4.要求查询姓名、年级名、成绩
  13. SELECT s.name,g.name,score
  14. FROM student s,grade g,result r
  15. WHERE s.id=r.student
  16. AND g.id=s.gradeid;
  17. #5.显示当前日期,以及去前后空格,截取子字符串的函数
  18. SELECT now();
  19. SELECT trim(' ' from ' sadjf ');
  20. SELECT substr(str,startIndex,length);

SQL99语法 

  1. # 4.SQL99语法
  2. # 内连接
  3. - 语法:
  4. select 查询列表
  5. from1 别名
  6. innerjoin2 别名 on 连接条件
  7. where 筛选条件
  8. group by 分组列表
  9. having 分组后的筛选
  10. order by 排序列表
  11. limit 子句;
  12. - 特点:
  13. ① 表的顺序可以调换
  14. ② 内连接的结果=多表的交集
  15. ③ n表连接至少需要n-1个连接条件
  16. - 分类:
  17. 等值连接
  18. 非等值连接
  19. 自连接
  20. #1.(一)等值连接
  21. - 案例1:查询员工名、部门名(调换位置)
  22. SELECT last_name,department_name
  23. FROM employees e
  24. INNER JOIN department d
  25. ON e.department_id =d.department_id;
  26. - 案例2:查询名字中包含e的员工名和工种名
  27. SELECT last_name,job_id
  28. FROM employees e
  29. INNER JOIN deaprtment d
  30. on e.job_id=j.job_id
  31. WHERE e.last_name LIKE "%e%";
  32. # 案例3:查询部门个数>3的城市名和部门个数(筛选+分组)
  33. SELECT city,COUNT(*) 个数
  34. FROM employees e
  35. INNER JOIN locations l
  36. ON e.department_id = l.location_id
  37. GROUP BY city
  38. HAVING COUNT(*)>3;
  39. # 案例4:查询哪个部门的部门员工个数>3的部门名 和 员工个数,并按个数降序
  40. SELECT COUNT(*) 个数,department_name
  41. FROM employees e
  42. INNER JOIN departments d
  43. ON e.department_id=d.department_id
  44. ORDER BY department_name
  45. HAVING COUNT(*)>3
  46. ORDER BY COUNT(*) DESC;
  47. # 案例5:查询员工名、部门名、工种名,并按部门名降序
  48. SELECT last_name, department_name, job_title
  49. FROM employees e
  50. INNER JOIN departments d ON e.department_id=d.department_id
  51. inner join jobs j ON e.job_id=j.job_id
  52. ORDER BY department_name DESC;
  53. # (二)非等值连接
  54. # 案例1:查询员工的工资级别
  55. SELECT salary,grade_lavel
  56. FROM employees e
  57. INNER JOIN job_grades g
  58. ON e.salary BETWEEN g.lowest_sal AND g.highest_sal;
  59. # 案例2: 查询工资级别的个数>20的个数,并按工资级别降序
  60. SELECT grade_level,COUNT(*)
  61. FROM employees e
  62. INNER JOIN job_grades g
  63. ON e.salary BETWEEN g.lowest AND g.highest
  64. GROUP BY grade_level
  65. HAVING COUNT(*)>20
  66. ORDER BY grade_level DESC;
  67. # (三)自连接
  68. #案例1:查询员工的名字和上级的名字
  69. SELECT e.last_name,m.last_name
  70. FROM employees e
  71. INNER JOIN employees m
  72. ON e.manager_id=m.employee_id;
  1. # 二、外连接
  2. #用于查询一个表中有,一个表中没有的情况
  3. #主表中所有内容:两个表的交集(内连)+主表中有而附表中没有的部分(NULL)
  4. - 特点:
  5. ① 查询的结果为主表中所有的行(记录),
  6. 如果从表和它匹配的将显示匹配行,如果从表没有匹配的则显示null
  7. 外连接查询结果=内连接结果+主表中有而从表中没有的记录
  8. left join 左边的就是主表
  9. right join 右边的就是主表
  10. full join 两边都是主表
  11. ③ 一般用于查询除了交集 部分的剩余的不匹配的行
  12. - 语法:
  13. select 查询列表
  14. from1 别名
  15. left|right|fullouterjoin2 别名 on 连接条件
  16. where 筛选条件
  17. group by 分组列表
  18. having 分组后的筛选
  19. order by 排序列表
  20. limit 子句;
  21. #引入:查询男朋友不在男神表中的女神名
  22. SELECT b.name
  23. FROM beauty b
  24. LEFT OUTER JOIN boys bo
  25. ON b.boyfrien_id = bo.id
  26. WHERE bo.id IS NULL;
  27. SELECT b.name
  28. FROM boys bo
  29. RIGHT OUTER JOIN beauty b
  30. ON b.boyfrien_id = bo.id
  31. WHERE bo.id IS NULL;
  32. # 查询每个部门没有员工?
  33. #左外
  34. SELECT department
  35. FROM departmnet d
  36. LEFT OUTER JOIN employees e
  37. ON d.department_id=e.department_id
  38. WHERE e.employee_id IS NULL;
  39. # 右外
  40. SELECT department
  41. FROM employees e
  42. RIGHT OUTER JOIN department d
  43. ON e.department_id=d.department_id
  44. WHERE e.employee_id IS NULL;
  45. #全外连接
  46. SELECT b.*,bo.*
  47. FROM beauty b
  48. FULL OUTER JOIN boys bo
  49. ON b.boyfriend_id=bo.id;
  50. --全外连接:交集部分(内连接结果)+beauty中有boys中没有的(LEFT外连接) + boys中有beautys没有的(RIGHT外连接)

  1. #1. 查询编号>3的女神的男朋友信息,如果有则列出详细,如果没有用NULL填充
  2. SELECT b.id, b.name, bo.*
  3. FROM beauty b
  4. LEFT OUTER JOIN boys bo
  5. ON b.boyfriend_id=bo.id
  6. WHERE b.id > 3;
  7. #2. 查询哪个城市没有部门
  8. SELECT city,d.*
  9. FROM locations l
  10. LEFT OUTER JOIN departments d
  11. ON l.location_id =d.location_id
  12. WHERE d.department_id IS NULL;
  13. #3. 查询部门名为SAL或者IT的员工信息
  14. --部门中也有可能没有员工,因此内连接查不全,用外连接
  15. SELECT e.*,d.department_name
  16. FROM employees e
  17. RIGHT OUTER JOIN department d --部门必须全查出来,但是员工可能没有
  18. ON e.department_id=d.department_id
  19. WHERE d.department_name IN('SAL','IT');

7. 子查询

  1. # 含义:
  2. # 子查询或内查询:出现在其他语句中的SLELCT语句。增删改查
  3. # 主查询或者外查询:内部嵌套其他select语句的查询
  4. # 按子查询出现的位置:
  5. select后面:
  6. 仅仅支持标量子查询
  7. from后面:
  8. 支持表子查询
  9. wherehaving后面:★
  10. 标量子查询(单行) √
  11. 列子查询(多行) √
  12. 行子查询
  13. exists后面(相关子查询):
  14. 表子查询
  15. # 按结果集的行列数不同:
  16. 标量子查询(结果集只有一行一列)
  17. 列子查询(结果集只有一列多行)
  18. 行子查询(结果集可以有一行多列)
  19. 表子查询(结果集一般为多行多列)

一、WHERE和HAVING后面的子查询

  1. # 一、WHEREHAVING后面的子查询
  2. # 1. 标量子查询(单行子查询)
  3. # 2. 列子查询(多行子查询)
  4. # 3. 行子查询(多列多行)
  5. # 特点:
  6. # ①:子查询放在小括号内
  7. # ②:子查询一般放在条件右侧
  8. # ③:标量子查询:一般搭配单行操作符使用。
  9. # > < >= <= = <>
  10. # 列子查询(多行):一般搭配多行操作符使用
  11. # INANY/SOMEALL
  12. # ④:子查询执行优先于主查询执行。
  13. #案例1:谁的工资比Abel高?
  14. # ① 查询Abel的工资
  15. SELECT salary
  16. FROM employees
  17. WHERE last_name = "Abel"
  18. # ② 查询谁的工资大于它
  19. SELECT *
  20. FROM employees e
  21. WHERE salary > ( SELECT salary
  22. FROM employees
  23. WHERE last_name = "Abel" );
  24. # 案例2:返回job_id与141号员工相同,salary比143号员工多的员工姓名,job_id和工资
  25. # ① 查询141号员工的job_id
  26. SELECT job_id
  27. FROM employees
  28. WHERE employee_id = 141;
  29. # ② 查询143号员工的salary
  30. SELECT salary
  31. FROM employees
  32. WHERE employee_id = 143;
  33. # 查询员工的姓名,job_id和工资,要求job_id=①,salary>
  34. SELECT last_name, job_id, salary
  35. FROM employees
  36. WHERE job_id=(SELECT job_id
  37. FROM employees
  38. WHERE employee_id = 141) AND salary > (SELECT salary
  39. FROM employees
  40. WHERE employee_id = 143);
  41. # 案例3:返回工资最少的员工的last_name,job_id和salary
  42. # ① 查询公司的最低工资
  43. SELECT MIN(salary)
  44. FROM employees;
  45. # ② 查询last_name,job_id和salary,要求salsry=
  46. SELECT last_name, job_id, salary
  47. FROM employees
  48. WHERE salary = ( SELECT MIN(salary)
  49. FROM employees );
  50. # 案例4:返回最低工资大于50号部门最低工资的部门id和其他最低工资
  51. # ① 查询50号部门最低工资
  52. SELECT MIN(salary)
  53. FROM employees
  54. WHERE department_id=50;
  55. # ② 查询每个部门的最低工资
  56. SELECT MIN(salary) min_salary,department
  57. FROM employees
  58. GROUP BY department_id;
  59. # ③ 筛选②,满足min_salary >
  60. SELECT department_id,MIN(salary)
  61. FROM employees
  62. GROUP BY department_id
  63. HAVING MIN(salary) > ( SELECT MIN(salary) min_salary
  64. FROM employees
  65. WHERE department_id=50 );
  66. # 非法使用标量子查询
  67. 1、子查询查出来的结果不是标量,不是一行一列
# 2. 列子查询(多行子查询,一列多行)

  1. --NOT IN 和 <>ALL
  2. --IN 和 = ANY
  3. # 案例1:返回location_id 是14001700的部门中的所有员工姓名
  4. # ① 查询location_id是14001700的部门编号
  5. SELECT department_id
  6. FROM departments
  7. WHERE location_id IN (1400,1700);
  8. # ② 查询员工姓名,要求部门号是①列表中的某一个
  9. SELECT last_name
  10. FROM employees
  11. WHERE department_id IN (
  12. SELECT department_id
  13. FROM departments
  14. WHERE location_id IN (1400,1700)
  15. );
  16. --或
  17. SELECT last_name
  18. FROM employees
  19. WHERE department_id =ANY (
  20. SELECT department_id
  21. FROM departments
  22. WHERE location_id IN (1400,1700)
  23. );
  24. #案例2:返回其它工种中比job_id为“IT_PROG”工种任一工资低的员工的员工号、姓名、job_id以及salary
  25. # ① job_id为IT_PROG部门的工资列表 ⭐⭐
  26. SELECT DISTINCT salary
  27. FROM employees
  28. WHERE job_id = “IT_PROG”;
  29. # ② 其他部门中的员工的信息,其工资大于列表①中的任一元素
  30. SElECT employee_id, last_name, job_id, salary
  31. FROM employees
  32. WHERE salary < ANY (
  33. SELECT DISTINCT salary
  34. FROM employees
  35. WHERE job_id = “IT_PROG”
  36. ) AND job_id <> "IT_PROG" ;
  37. --或
  38. SElECT employee_id, last_name, job_id, salary
  39. FROM employees
  40. WHERE salary < (
  41. SELECT MAX(salary)
  42. FROM employees
  43. WHERE job_id = “IT_PROG”
  44. ) AND job_id <> "IT_PROG" ;
  45. #案例3:返回其它工种中比job_id为“IT_PROG”工种所有工资低的员工的员工号、姓名、job_id以及salary
  46. # ① job_id为IT_PROG部门的工资列表
  47. SELECT DISTINCT salary
  48. FROM employees
  49. WHERE job_id = “IT_PROG”;
  50. # ② 其他部门中的员工的信息,其工资大于列表①中的任一元素
  51. --或
  52. SElECT employee_id, last_name, job_id, salary
  53. FROM employees
  54. WHERE salary < (
  55. SELECT MIN(salary)
  56. FROM employees
  57. WHERE job_id = “IT_PROG”
  58. ) AND job_id <> "IT_PROG" ;
  1. 3. 行子查询(一行多列,多行多列)
  2. #案例:查询员工编号最小并且工资最高的员工信息⭐⭐
  3. --具备这样条件的员工不一定存在
  4. # 原来方法:
  5. # ① 查询最小员工编号
  6. SELECT MIN(employee_id)
  7. FROM employees
  8. # ② 查询最高工资
  9. SELECT MAX(salary)
  10. FROM employees
  11. # ③ 查询员工信息,要求
  12. SELECt *
  13. FROM employees
  14. WHERE employee_id=(
  15. SELECT MIN(employee_id)
  16. FROM employees
  17. )
  18. AND
  19. salary = (
  20. SELECT MAX(salary)
  21. FROM employees
  22. );
  23. # 行子查询:多个条件使用一样的操作符好
  24. SELECT *
  25. FROM employees
  26. WHERE (employee_id, salary) = (
  27. SELECT MIN(employee_id),MAX(salary)
  28. FROM employees
  29. )

二、SELECT后面

  1. # SELECT后面放一行 一列 !!
  2. # 案例1:查每个部门的员工个数(在部门表中加一 个数 列)
  3. SELECT d.*, (
  4. SELECT COUNT(*)
  5. FROM employees
  6. WHERE e.department_id = d.department_id
  7. )
  8. FROM departments d;
  9. #案例2:查询员工号=102的部门名
  10. SELECT (
  11. SELECT d.department_name --只能查一个属性:一列
  12. FROM departments d
  13. INNER JOIN employees e
  14. ON e.departmnt_id = d.department_id
  15. WHERE e.employee_id=102
  16. ) 部门名 ;

三、FROM后面

  1. # FROM后面的子查询: 结果集是一个表
  2. # 将子查询结果充当一张表,要求必须取别名
  3. # 案例1:查询每个部门的平均工资的工资等级 ⭐⭐
  4. # ① 查询每个部门的平均工资————得到了平均工资表ag_dep
  5. SELECT AVG(salary) avg(salary) , department_id
  6. FROM employees e
  7. GROUP BY department_id;
  8. # ② 根据登记表进行工资等级判断————表的连接:ag_dep和job_grades表
  9. SELECT ag_dep.*, j.grade_lavel salary_level
  10. FROM (
  11. SELECT AVG(salary) ag , department_id
  12. FROM employees e
  13. GROUP BY department_id
  14. ) ag_dep
  15. INNER JOIN job_grades j
  16. ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;

四、EXISTS后面的子查询(相关子查询)

  1. # 语法:
  2. EXIST(完整的查询语句)
  3. 结果: 1或者0
  4. SELECT EXISTS( SELECT employee_id FROM employees WHERE salary=300000); #结果为0
  5. # 案例1:查询有员工的部门名
  6. SELECT department_name
  7. FROM departments d
  8. WHERE EXISTS(
  9. SELECT *
  10. FROM employees e
  11. WHERE d.department_id = e.department_id --满足这个条件的有没有
  12. )
  13. --或
  14. # IN方法
  15. SELECT department_name
  16. FROM departments d
  17. WHERE d.department_id IN (
  18. SELECT department_id
  19. FROM employees
  20. )
  21. # 查询没有女朋友的男神信息 ⭐⭐
  22. SELECT *
  23. FROM boys bo
  24. WHERE NOT EXISTS(
  25. SELECT boyfroend_id
  26. FROM beauty b
  27. WHERE bo.id = b.boyfriend_id
  28. );
  29. #IN方法
  30. SELECT *
  31. FROM boys
  32. WHERE boys.id NOT IN (
  33. SEKECT boyfriend_id
  34. FROM beauty
  35. );
  1. --标量子查询
  2. #1.查询和zlotkey相同部门的员工姓名和工资
  3. SELECT last_name, salary
  4. FROM employees
  5. WHERE department_id = (
  6. SELECT department_id
  7. FROM employees
  8. WHERE last_name ='zlotkey'
  9. );
  10. #2.查询工资比公司平均工资高的员工的员工号,姓名,工资
  11. SELECT employee_id, last_name, salary
  12. FROM employees
  13. WHERE salary > (
  14. SELECT AVG(salary)
  15. FROM employees
  16. );
  1. #多行多列子查询——from后面
  2. #3.查询各部门中工资比本部门平均工资高的员工的员工号,姓名和工资 ⭐⭐
  3. SELECT employee_id, last_name, salary
  4. FROM employees e
  5. INNER JOIN (
  6. SELECT AVG(salary) ag_sal, department_id
  7. FROM employees
  8. GROUP BY department_id
  9. ) ag_dep
  10. ON e.department_id = ag_dep.department_id
  11. WHERE e.salary > ag_dep.sg_sal;
  1. # 一列多行用 IN
  2. #4.查询 和姓名中包含字母u的员工在相同部门的员工的员工号和姓名 ⭐⭐
  3. SELECT employee_id, last_name, department_id
  4. FROM employees e
  5. WHERE department_id IN(
  6. SELECT DISTINCT department_id
  7. FROM employees
  8. WHERE last_name LIKE "%u%"
  9. );
  1. #5.查询在部门的location_id为1700的部门工作的员工的员工号。 ⭐⭐
  2. SELECT employee_id
  3. FROM employees
  4. WHERE department_id = ANY( -- =ANY可以换成IN
  5. SELECT DISTINCT department_id
  6. FROM departments
  7. WHERE location_id =1700
  8. );
  1. # 一列多行
  2. #6.查询管理者为King的员工姓名和工资 ⭐⭐
  3. SELECT last_name, salary
  4. FROM employees
  5. WHERE manager_id IN (
  6. SELECT employee_id
  7. FROM employees
  8. WHERE last_name="King" --管理者King的员工号
  9. )
  1. #7.查询工资最高的员工的姓名,要求first_name和last_name显示为一列,列名为姓名⭐⭐
  2. SELECT CONCAT(first_name, last_name) "姓.名"
  3. FROM employees
  4. WHERE salary = (
  5. SELECT MAX(salary)
  6. FROM employees
  7. );

8. 分页查询

  1. # 应用场景
  2. 当要显示的数据,一页显示不全,需要分页提交SQL请求
  3. # 语法:
  4. select 查询列表
  5. from
  6. join type】 join2
  7. on 连接条件
  8. where 筛选条件
  9. group by 分组字段
  10. having 分组后筛选
  11. order by 排序的字段
  12. limit offset,size; --offset要显示条目的起始索引(起始索引从0开始);size表示要显示的条目个数
  13. #案例1:查询前五条员工信息
  14. SELECT * FROM employees LIMIT 0,5;
  15. #案例2:查询第11-25
  16. SELECT * FROM employees LIMIT 10,15;
  17. #案例3:查询有奖金的员工信息,并且工资较高的前十名
  18. SELECT *
  19. FROM employees
  20. WHERE commissiom_pct IS NOT NULL
  21. ORDER BY salary DESC
  22. LIMIT 10;
  23. #特点
  24. ① LIMIT语句要放在查询语句的最后
  25. ② 公式:
  26. 要显示的页数 page,每页的条目数是size
  27. SELECT 查询列表
  28. FROM
  29. LIMIT (page-1)*size,size; --每一页的起始页数
  30. size=10
  31. page (page-1)*size
  32. 1 0
  33. 2 10
  34. 3 20
  1. 已知表 stuinfo
  2. id 学号
  3. name 姓名
  4. email 邮箱 john@126.com
  5. gradeID 年级编号
  6. sex 性别 男 女
  7. age 年龄
  8. 已知表 grade
  9. id 年纪编号
  10. gradeName 年纪名称
  11. #案例1:查询所有学员的邮箱的用户名(邮箱中@前面的字符) SUBSTR函数、INSTR函数
  12. SELECT SUBSTR(email,1,INSTR(email,'@')-1)
  13. FROM stuinfo;
  14. #案例2:查询男生和女生的个数
  15. SELECT COUNT(*) 个数,sex
  16. FROM stuinfo
  17. GROUP BY sex;
  18. #案例3:查询年龄>18岁的所有学生的姓名和年纪名称
  19. SELECT name,gradeName
  20. FROM stuinfo s
  21. INNER JOIN grade g
  22. ON s.gradeID = g.id
  23. WHERE age>18;
  24. #案例4:查询哪个年纪的学生最小年龄>20岁:首先查询每个年级的最小年龄
  25. SELECT min(age),gradeID
  26. FROM stuinfo
  27. GROUP BY gradeID
  28. HAVING min(age)>20;
  29. #案例5:试说出查询语句中涉及到的所有关键字,以及执行先后顺序
  30. SELECT 查询列表 7
  31. FROM1
  32. 连接类型 JOIN2 2
  33. ON 连接条件 3
  34. WHERE 筛选条件 4
  35. GROUP BY 分组列表 5
  36. HAVING 分组后筛选 6
  37. ORDER BY 排序列表 8
  38. LIMIT 偏移,条目数 9
  1. #示例
  2. #1. 标量子查询
  3. #案例:查询最低工资的员工姓名和工资
  4. #① 最低工资
  5. SELECT min(salary) FROM employees
  6. #② 查询员工的姓名和工资,要求工资等于①
  7. SELECT last_name, salary
  8. FROM employees
  9. WHERE salary = (
  10. SELECT min(salary) FROM employees
  11. );
  12. #2.列子查询
  13. #案例:查询所有时领导的员工姓名
  14. ① 查询所有员工的manager_id
  15. SELECT manager_id
  16. FROM employees;
  17. #② 查询领导对应的名字
  18. SELECT last_name
  19. FROM employees
  20. WHERE employee_id IN (
  21. SELECT manager_id
  22. FROM employees
  23. );

 下面第3、8题。

  1. #1. 查询工资最低的员工信息:last_name, salary
  2. SELECT last_name, salary
  3. FROM employees
  4. WHERE salary = (
  5. SELECT min(salary) FROM employees;
  6. );
  7. #2. 查询平均工资最低的部门信息
  8. 方法一:
  9. ① 各部门平均工资
  10. SELECT AVG(salary) , department_id
  11. FROM employees
  12. GROUP BY department_id;
  13. ② 最低平均工资;
  14. SELECT min(AVG(salary))
  15. FROM (
  16. SELECT AVG(salary) , department_id
  17. FROM employees
  18. GROUP BY department_id
  19. ) ag_dep;
  20. ③ 查询哪个部门的平均工资=
  21. SELECT AVG(salary), department_id
  22. FROM employees
  23. GROUP BY department_id
  24. HAVING AVG(salary) = (
  25. SELECT min(AVG(salary))
  26. FROM (
  27. SELECT AVG(salary) , department_id
  28. FROM employees
  29. GROUP BY department_id
  30. ) ag_dep;
  31. );
  32. ④ 查询部门信息
  33. SELECT d.*
  34. FROM departments
  35. WHERE d.department_id =
  36. (
  37. SELECT department_id
  38. FROM employees
  39. GROUP BY department_id
  40. HAVING AVG(salary) = (
  41. SELECT min(AVG(salary))
  42. FROM (
  43. SELECT AVG(salary) , department_id
  44. FROM employees
  45. GROUP BY department_id
  46. ) ag_dep;
  47. );
  48. --方式二:
  49. ① 各部门平均工资
  50. SELECT AVG(salary) , department_id
  51. FROM employees
  52. GROUP BY department_id;
  53. ② 求出最低平均工资的部门编号
  54. SELECT department_id
  55. FROM employees
  56. GROUP BY department_id
  57. ORDER BY AVG(salary) ASC
  58. LIMIT 1;
  59. ③ 查询部门信息
  60. SELECT d.*
  61. FROM departments d
  62. WHERE department_id = (
  63. SELECT department_id
  64. FROM employees
  65. GROUP BY department_id
  66. ORDER BY AVG(salary) ASC
  67. LIMIT 1;
  68. );
  69. 3. 查询平均工资最低的部门信息和该部门的平均工资
  70. ① 求每个部门的平均工资
  71. SELECT AVG(salary),department_id
  72. FROM employees
  73. GROUP BY department_id;
  74. ② 查询平均工资最低的部门编号和平均工资
  75. SELECT AVG(salary), department_id
  76. FROM employees
  77. GROUP BY department_id
  78. ORDER BY AVG(salary) ASC
  79. LIMIT 1;
  80. ③ 查询部门信息和该部门的平均工资
  81. SELECT d.*, ag
  82. FROM departments d
  83. INNER JOIN (
  84. SELECT AVG(salary) ag, department_id
  85. FROM employees
  86. GROUP BY department_id
  87. ORDER BY AVG(salary) ASC
  88. LIMIT 1
  89. ) ag_dep
  90. ON d.department_id=ag_dep.department_id;
  91. #4. 查询平均工资最高的job信息
  92. #① 每个job的平均工资
  93. SELECT AVG(salary), job_id
  94. FROM employees
  95. GROUP BY job_id
  96. ORDER BY AVG(salary) DESC
  97. LIMIT 1;
  98. #② 查询job信息
  99. SELECT *
  100. FROM jobs
  101. WHERE jobs.job_id=(
  102. SELECT job_id
  103. FROM employees
  104. GROUP BY job_id
  105. ORDER BY AVG(salary) DESC
  106. LIMIT 1
  107. );
  108. --如果需要给出平均工资最高的job信息和平均最高工资,需要用来连接
  109. SELECT j.*AVG(salary)
  110. FROM jobs
  111. INNER JOIN (
  112. SELECT AVG(salary), job_id
  113. FROM employees
  114. GROUP BY job_id
  115. ORDER BY AVG(salary) DESC
  116. LIMIT 1
  117. ) ag_job
  118. ON jobs.job_id=ag_job.job_id;
  119. #5. 查询平均工资高于公司平均工资的部门有哪些?
  120. #① 先查公司平均工资
  121. SELECT AVG(salary)
  122. FROM employees;
  123. #② 查每个部门的平均工资
  124. SELECT AVG(salary),department_id
  125. FROM employees
  126. GROUP BY department_id;
  127. #③ 平均工资 > ①的部门
  128. SELECT AVG(salary),department_id
  129. FROM employees
  130. GROUP BY department_id
  131. WHERE AVG(salary) > (
  132. SELECT AVG(salary)
  133. FROM employees
  134. );
  135. #6. 查询出公司中所有 manager 的详细信息
  136. #① 查出所有manager的id
  137. SELECT DISTINCT manager_id
  138. FROM employees;
  139. #② 根据manager_id查出manager的信息
  140. SELECT *
  141. FROM employees
  142. WHERE employee_id IN ( --或者 = ANY( )
  143. SELECT manager_id
  144. FROM employees
  145. );
  146. #7. 各部门中 最高工资中最低的那个部门的 最低工资时多少
  147. #① 每个部门的最高工资
  148. SELECT MAX(salary), department_id
  149. FROM employees
  150. GROUP BY department_id;
  151. #② 所有部门的最高工资中最低的部门编号
  152. SELECT MAX(salary), department_id
  153. FROM employees
  154. GROUP BY department_id
  155. ORDER BY MAX(salary) ASC
  156. LIMIT 1;
  157. #③ 部门②中的最低工资
  158. SELECT MIN(salary)
  159. FROM employees
  160. WHERE department_id=(
  161. SELECT department_id
  162. FROM employees
  163. GROUP BY department_id
  164. ORDER BY MAX(salary) ASC
  165. LIMIT 1
  166. );
  167. #8. 查询平均工资最高的部门的manager的详细信息:lsat_name,department_id,email,salary
  168. #① 查询平均工资最高的部门编号
  169. SELECT department_id
  170. FROM employees
  171. GROUP BY department_id
  172. ORDER BY AVG(salary) DESC
  173. LIMIT 1;
  174. #② 将employees和departments表连接查询,筛选条件是①
  175. SELECT lsat_name,department_id,email,salary
  176. FROM employees e
  177. INNER JOIN departments d
  178. ON d.manager_id=e.employee_id
  179. WHERE d.department_id=(
  180. SELECT department_id
  181. FROM employees
  182. GROUP BY department_id
  183. ORDER BY AVG(salary) DESC
  184. LIMIT 1
  185. );

 第5\6\7\8题

  1. #1. 查询每个专业的学生人数
  2. SELECT majorid, COUNT(*)
  3. FROM student
  4. GROUP BY major ;
  5. #2. 查询参加考试的学生中,每个学生的平均分,最高分
  6. SELECT studentno, AVG(score), MAX(score)
  7. FROM result
  8. GROUP BY studentno;
  9. #3. 查询姓张的每个学生的最低分大于60的学号、姓名
  10. SELECT s.studentno, s.studentname, MIN(score)
  11. FROM result r
  12. INNER JOIN student s
  13. ON r.studentno=s.studentno
  14. WHERE s.studentname LIKE "张%"
  15. GROUP BY studentno
  16. HAVING MIN(score) > 60;
  17. #4. 查询生日在“1988-1-1”后的学生的姓名、专业名称
  18. SELECT studentname, loginpwd, majorname
  19. FROM student s
  20. JOIN major m ON s.majorid=m.majorid
  21. JOIN result r ON s.studentno=r.studentno
  22. WHERE r.score>60;
  23. SELECT s.studentname, m.majorname
  24. FROM student s
  25. INNER JOIN major m
  26. ON s.majorid=m.majorid
  27. WHERE DATEDIFF(borndate,"1988-1-1") > 0; --如果borndate大于后面的日期就返回正数
  28. #5. 查询每个专业的男生人数和女生人数分别是多少
  29. SELECT majorid,
  30. (SELECT COUNT(*) FROM student WHERE sex="男" AND majorid=s.majorid ) 男,
  31. (SELECT COUNT(*) FROM student WHERE sex="女" AND majorid=s.majorid ) 女
  32. FROM student s
  33. GROUP BY majorid;
  34. #6. 查询专业和张翠山一样的学生的最低分
  35. SELECT majorid
  36. FROM student
  37. WHERE studentname = "张翠山";
  38. SELECT studentno FROM student WHERE majorid=(
  39. SELECT majorid
  40. FROM student
  41. WHERE studentname = "张翠山"
  42. );
  43. SELECT MIN(score)
  44. FROM result
  45. WHERE studentno IN (
  46. SELECT studentno
  47. FROM student
  48. WHERE majorid=(
  49. SELECT majorid
  50. FROM student
  51. WHERE studentname = "张翠山"
  52. )
  53. );
  54. --或者
  55. SELECT MIN(score)
  56. FROM result r
  57. INNER JOIN student s
  58. ON r.studentno=s.studentno
  59. WHERE s.majorid=(
  60. SELECT majorid
  61. FROM student
  62. WHERE studentname = "张翠山"
  63. );
  64. #7. 查询大于60分的学生的姓名,密码,专业名
  65. SELECT studentname, loginpwd, majorid
  66. FROM student
  67. INNER JOIN result
  68. ON student.studentno=result.studentno
  69. WHERE score > 60;
  70. --或者
  71. SELECT studentname, loginpwd, majorname
  72. FROM (
  73. SELECT studentname, loginpwd, majorid
  74. FROM student
  75. INNER JOIN result
  76. ON student.studentno=result.studentno
  77. WHERE score > 60
  78. ) ss
  79. INNER JOIN major m
  80. ON ss.majorid=m.majorid;
  81. #8. 按邮箱位数分组,查询每组学生的个数
  82. SELECT COUNT(*), LENGTH(email)
  83. FROM student
  84. GROUP BY LENGTH(email);
  85. #9. 查询学生名,专业名,分数
  86. SELECT studentname, score, majorid
  87. FROM student s
  88. JOIN result r ON s.studentno= r.studentno
  89. JOIN major m ON s.majorid= m.majorid;
  90. #10. 查询那个专业(主表)没有学生,分别用左连接和右连接实现
  91. SELECT DISTINCT m.majorid, m.majorname,
  92. FROM major m
  93. LEFT JOIN student s
  94. ON m.majorid=s.majorid
  95. WHERE s.studentno IS NULL;
  96. --右连接
  97. SELECT DISTINCT majirid
  98. FROM student s
  99. RIGHT JOIN major m
  100. ON s.majorid=m.majorid
  101. WHERE studentno IS NULL;
  102. #11. 查询没有成绩的学生(主表)人数
  103. SELECT COUNT(*)
  104. FROM student s
  105. JOIN result r
  106. ON s.studentno=r.studentno
  107. WHERE r.score = NULL;

9. 联合查询(尚硅谷-124节)

  1. # 1. 联合查询 UNION : 将多条查询语句的结果合并成一个结果
  2. 查询语句1
  3. unionall
  4. 查询语句2
  5. unionall
  6. ...
  7. # 2. 应用场景:
  8. 要查询的结果来自于多个表,且多个表没有直接的连接关系,但查询的列一致时
  9. # 3. 特点:★
  10. 3.1 要求多条查询语句的查询列数是一致的!
  11. 3.2 要求多条查询语句的查询的每一列的类型和顺序最好一致
  12. 3.3 union关键字默认去重,如果使用union all 可以包含重复项
  13. # 4.案例:查询部门编号>90或邮箱包含a的员工信息
  14. SELECT * FROM employees WHERE email LIKE '%a%' OR department_id>90;;
  15. SELECT * FROM employees WHERE email LIKE '%a%'
  16. UNION
  17. SELECT * FROM employees WHERE department_id>90;
  18. # 案例:查询中国用户中男性的信息以及外国用户中男性的信息(两个表中没有连接关系)
  19. SELECT id, cname, csex FROM t_ca WHERE csex="男";
  20. UNION
  21. SELECT id, tname, tgender FROM t_ua WHERE tgender="male";
  1. # 语法以及执行顺序
  2. select 查询列表 ⑦
  3. from1 别名 ①
  4. 连接类型 join2
  5. on 连接条件 ③
  6. where 筛选 ④
  7. group by 分组列表 ⑤
  8. having 筛选 ⑥
  9. order by排序列表 ⑧
  10. limit 起始条目索引,条目数; ⑨

 (三)DML语言

数据操作语言——对数据的操作

        插入:insert

        修改:update

        删除:delete

 3.1 插入语句

  1. # 表已经存在,需要在表中插入信息(表名、列名、新值)
  2. # 语法:
  3. INSERT INTO 表名(列名,...) values(值1,...);
  4. # 特点
  5. 1、要求值得类型和字段得类型(列类型)一致或兼容
  6. 2、字段个数和顺序不一定要与原始表中得字段个数和顺序一致,但必须保证值和字段一一对应
  7. 3、假如表中有可以为NULL的字段,注意可以通过以下两种方式插入NULL
  8. ①字段和值都省略
  9. ②字段写上,只是用null
  10. 4、字段和值得个数必须一致
  11. 5、字段名可以省略,默认所有列
  12. # 1. 插入的值得类型要与列得类型一致或兼容
  13. INSERT INTO beauty(id, NAME, sex, borndate, phone, photo,boyfriend_id)
  14. VALUES(13,"唐艺昕","女","1990-04-23","18988888888",NULL,2);
  15. --照片类型暂时不能插入,用NULL代替
  16. # 2. 不可以为NULL的列必须插入值,可以为NULL的列如何插入值?
  17. --方式一:列名写着,值用NULL填充
  18. INSERT INTO beauty(id, NAME, sex, borndate, phone, photo,boyfriend_id)
  19. VALUES(13,"唐艺昕","女","1990-04-23","18988888888",NULL,2);
  20. --方式二:列名和值都省略
  21. INSERT INTO beauty(id, NAME, sex, phone)
  22. VALUES(14,"金星","女", "13288888888");
  23. # 3. 列的顺序是否可以调换? 可以
  24. INSERT INTO beauty(sex, phone, id, NAME)
  25. VALUES("女", "13288888888", 14,"金星");
  26. # 4. 列数和值的个数必须一致。
  27. INSERT INTO beauty(sex, phone, id, NAME, friend_id)
  28. VALUES("女", "13288888888", 14,"金星");
  29. # 5. 可以省略列名,默认是所有列名,而且列名的顺序和表中的列顺序一致。
  30. INSERT INTO beauty
  31. VALUES(18, '张飞', '男', NULL, '119', NULL, NULL);
  32. --方式二
  33. #语法
  34. INSERT INTO 表名 SET 列名=值,列名=值,...
  35. #案例
  36. INSERT INTO beauty
  37. SET id=10, '刘涛', phone='999'; --出生日期有默认值,可以不写
  38. # 两种方式大PK————插入多行、子查询
  39. 1、 方式一支持插入多行,方式二不支持
  40. --INSERT INTO 表名【(字段名...)】 VALUES(值,...)
  41. INSERT INTO beauty
  42. VALUES (13,"唐艺昕","女","1990-04-23","18988888888",NULL,2)
  43. , (13,"唐艺昕","女","1990-04-23","18988888888",NULL,2)
  44. , (13,"唐艺昕","女","1990-04-23","18988888888",NULL,2);
  45. 2、方式一还支持子查询,方式二不支持
  46. --INSERT INTO 表名
  47. INSERT INTO beauty(id, NAME, phone)
  48. SELECT id, boyname, '19897376';
  49. FROM friend WHERE name="宋茜";

 3.2 修改语句

  1. # 1、修改单表的记录 ⭐
  2. # 语法
  3. UPDATE 表名
  4. SET=新值,列=新值,... 【修改多列】【不加where条件的话,就是所有行都修改】
  5. WHERE 筛选条件;
  6. 2、修改多表的记录【补充】
  7. # 语法:sql92(内连)
  8. UPDATE1 别名,表2 别名
  9. SET=值,...
  10. WHERE 连接条件
  11. and筛选条件
  12. #语法:sql99
  13. UPDATE1 别名
  14. INNER|LEFT|RIGHT JOIN2 别名
  15. ON 连接条件
  16. SET=值,...
  17. WHERE 筛选条件;
  18. #案例1:beauty表中 姓唐的女神的电话为232323
  19. UPDATE beauty SET phone='232323'
  20. WHERE name LIKE '唐%';
  21. #案例2:修改boys表中id为2的名称为张飞, 魅力值为10
  22. UPDATE boys SET boyname='张飞', usercp=10
  23. WHERE id=2;
  24. #案例1:修改张无忌的女朋友的手机号为114
  25. UPDATE boys bo
  26. INNER JOIN beauty b ON bo.id=b.boyfriend_id
  27. SET b.phone='114'
  28. WHERE bo.boyname='张无忌';
  29. #案例2:修改没有男朋友的女神的男朋友的id都为2
  30. UPDATE boys bo
  31. RIGHT JOIN beauty b ON bo.id=b.boyfriend_id
  32. SET b.boyfriend_id=2
  33. WHERE bo.id IS NULL;

3.3 删除语句 

  1. # 方法一:DELETE 只能删除整行
  2. # 语法:
  3. 1、单表的删除 ⭐
  4. DELETE FROM 表名 WHERE 筛选条件 【LIMIT 条目数】
  5. 2、多表的删除【补充】
  6. --sql92
  7. DELETE 要删除表的别名
  8. FROM1 别名,表2 别名
  9. WHERE 连接条件
  10. and 筛选条件;
  11. --sql99
  12. DELETE 要删除表的别名, 要删除表的别名
  13. FROM1 别名
  14. INNER|LEFT|RIGHT JOIN2 别名
  15. ON 连接条件
  16. WHERE 筛选条件;
  17. # 方式二:TRUNCATE
  18. # 语法:TRUNCATE TABLE 表名;
  19. # 方式一案例:delete
  20. # 1. 删除手机号以9结尾的女神信息
  21. DELETE FROM beauty WHERE phone LIKE '%9';
  22. # 2. 多表的删除:删除张无忌的女朋友的信息(女朋友是存在的,可以用内连接)
  23. DELETE b
  24. FROM beauty b
  25. INNER JOIN boys bo ON bo.id=b.boyfriend_id
  26. WHERE bo.boyName = '张无忌';
  27. # 3. 删除黄晓明的信息以及女朋友的信息
  28. DELETE b, bo
  29. FROM beauty b
  30. INNER JOIN boys bo ON b.id=bo.boyfroiend
  31. WHERE bo.boyname='黄晓明'; --【一共删除了两行,重新打开表看】
  32. # 4.删除第一条信息 OR 删除某一条信息
  33. DELETE FROM beauty LIMIT 1;
  34. DELETE FROM beauty WHERE boyfriend_id=4 LIMIT 1;
  35. # 方式二:truncate语句:清空数据表,删除多行
  36. TRUNCATE TABLE boys; 将boys表中的数据都删除
  37. # DELETE PK TRUNCATE ⭐面试题
  38. 1. delete可以加where筛选条件,truncate不能加
  39. 2. truncate删除,效率高一丢丢
  40. 3. 如果delete删除后要再插入数据,自增长列的值从断点开始,【删除了1-5的数据,再插入数据,从6开始增加】
  41. truncate删除后,再插入数据,自增长列的值从1开始。
  42. 4. truncate删除没有返回值,delete删除可以返回值影响的行数
  43. 5. truncate删除不能回滚,delete删除可以回滚。
  1. # 测试题
  2. # 运行以下脚本创建表my_employees
  3. USE myemployees;
  4. CREATE TABLE my_employees(
  5. ID INT(10),
  6. First_name VARCHAR(10),
  7. Last_name VARCHAR(10),
  8. Userid VARCHAR(10),
  9. Salary DOUBLE(10,2)
  10. );
  11. CREATE TABLE users(
  12. id INT,
  13. userid VARCHAR(10),
  14. department_id INT
  15. );
  16. # 显示表my_employees的结构
  17. DESC my_employees;
  18. # 向my_employees表中插入下列数据(一次性多行数据)
  19. 1 patel Ralph Rpatel 895
  20. 2 Dancs Betty Bdancs 860
  21. 3 Biri Ben Bbiri 1100
  22. 4 Newman Chad Cnewman 750
  23. 5 Ropeburn Audrey Aropebur 1550
  24. --方式一:
  25. INSERT INTO my_employees
  26. VALUES (1,'patel','Ralph','Rpatel',895),
  27. (2,'Dancs','Betty','Bdancs',860),
  28. (3,'Biri','Ben','Bbiri',1100),
  29. (4,'Newman','Chad','Cnewman',750),
  30. (5,'Ropeburn','Audrey','Aropebur',1550);
  31. --方式二:用联合查询
  32. INSERT INTO my_employees
  33. SELECT 1,'patel','Ralph','Rpatel',895 UNION
  34. SELECT 2,'Dancs','Betty','Bdancs',860 UNION
  35. SELECT 3,'Biri','Ben','Bbiri',1100 UNION
  36. SELECT 4,'Newman','Chad','Cnewman',750 UNION
  37. SELECT 5,'Ropeburn','Audrey','Aropebur',1550;
  38. #向users表中插入数据
  39. INSERT INTO users
  40. VALUES(1,'Rpatel',10'),
  41. (2,'Bdancs',10),
  42. (3,'Bbiri',20),
  43. (4,'Cnewman',30),
  44. (5,'Aropebur',40);
  1. # 将3号员工的last_name修改为“drelxer”
  2. UPDATE my_employees SET last_name='drelxer' WHERE id=3;
  3. # 将所有工资少于900的员工的工资修改为1000
  4. UPDATE my_employees SET salary=1000 WHERE salary<900;
  5. # 将userid为Bbiri的user表和my_employees表的记录全部删除
  6. DELETE u, m
  7. FROM users u
  8. INNER JOIN my_employees m on u.userid=m.Userid
  9. WHERE u.userid='Bbiri';
  10. # 删除所有数据
  11. DELETE FROM my_employees;
  12. DELETE FROM users;
  13. # 检查所作的修正;
  14. SELECT * FROM my_employees;
  15. SELECT * FROM users;
  16. # 清空表my_employees
  17. TRUNCATE TABLE my_employees;

(四)、DDL语言

4.1 数据定义语言——对库和表的管理

一、库的管理

        创建、修改、删除

二、表的管理

        创建、修改、删除

创建:CREATE

修改:库和表的结构 ALTER

删除:DROP

4.1.1 库的管理

  1. # 1、库的创建 CREATE
  2. # 语法:
  3. /*
  4. CREATE DATABASE [IF NOT EXISTS] 库名 【CHARACTER SET 字符集名】;
  5. */
  6. # 案例:创建库books
  7. CREATE DATABASE IF NOT EXISTS books;
  8. # 2、库的修改 ALTER
  9. # 一般来说,库不进行修改,否则容易出现问题/错误;库名一般也不修改
  10. # 以前有RENAME DATABASE books TO 新库名;不安全,现在不可以用
  11. # 要想进行【库名的修改】,在文件夹中重命名
  12. # 可以更改库的字符集
  13. ALTER DATABASE books CHARACTER SET gbk; [utf8 to gbk]
  14. # 3、库的删除 DROP
  15. /*
  16. DROP DATABASE IF EXISTS books;
  17. */

4.1.2 表的管理

  1. # 1、表的创建 ⭐
  2. # 语法:
  3. /*
  4. CREATE TABLE [IF NOT EXISTS] 表名(
  5. 列名 列的类型【(长度) 约束】,
  6. 列名 列的类型【(长度) 约束】,
  7. ......
  8. 列名 列的类型【(长度) 约束】
  9. );
  10. */
  11. # 案例:创建表Books
  12. CREATE TABLE IF NOT EXISTS Books(
  13. id INT, #编号
  14. b_name VARCHAR(20), #书名(最大长度)
  15. price DOUBLE, #价格
  16. author_id INT, #作者
  17. publishDate DATETIME #出版日期
  18. )
  19. DESC Books
  20. # 创建authors表
  21. CREATE TABLE authors(
  22. id INT,
  23. au_name VARCHAR(20),
  24. nation VARCHAR(10)
  25. );
  26. DESC authors;
  27. # 2、表的修改
  28. /*
  29. ALTER TABLE 表名 ADD|DROP|MODIFY|CHANGE|RENAME TO| COLUMN 列名 列类型 约束;
  30. */
  31. #(1)修改列名
  32. --ALTER TABLE 表名 CHANGE COLUMN 旧列名 新列名 类型;
  33. -- 将Books中的publishDate列修改为
  34. ALTER TABLE Books CHANGE COLUMN publishDate pubDate DATETIME; --顺便修改类型
  35. 2)修改列的类型或约束[默认值,长度]
  36. --ALTER TABLE 表名 MODIFY COLUMN 列名 新类型 【新约束】;
  37. ALTER TABLE Books MODIFY COLUMN pubDate TIMESTAMP;
  38. 3)添加列
  39. --ALTER TABLE 表名 ADD COLUMN 列名 类型 【first|after 字段名】;
  40. # 在authors表中列annual列
  41. ALTER TABLE authors ADD COLUMN annual DOUBLE ;
  42. 4)删除列
  43. --ALTER TABLE 表名 DROP COLUMN 列名;
  44. ALTER TABLE authors DROP COLUMN annual;
  45. 5)修改表名
  46. --ALTER TABLE 表名 RENAME 【TO】 新表名
  47. ALTER TABLE authors RENAME TO book_author;
  48. # 3、表的删除
  49. /*
  50. DROP TABLE 【IF EXISTS】book_author;
  51. SHOW TABLES; --查看当前库中的所有表
  52. */
  53. # 4、表的复制
  54. INSERT INTO authors VALUES
  55. (1,'村上春树','日本'),
  56. (2,'莫言','中国'),
  57. (3,'冯唐','中国'),
  58. (4,'金庸','中国');
  59. #1. 仅复制表的结构:复制列名和列类型,约束
  60. --CREATE TABLE 表名 LIKE 旧表;
  61. CREATE TABLE copy LIKE authors; --authors中有数据,从copy中没有数据
  62. #2. 复制表的结构+数据
  63. --CREATE TABLE 表名 SELECT 查询列表 FROM 旧表 【WHERE 筛选条件】;
  64. CREATE TABLE copy2
  65. SELECT * FROM authors; --从authors中复制结构和数据到copy2中
  66. #3. 复制部分数据
  67. --CREATE TABLE 表名 SELECT 查询列表 FROM 旧表 WHERE 筛选条件;
  68. CREATE TABLE copy3
  69. SELECT id,au_Name
  70. FROM authors
  71. WHERE nation='中国';
  72. #4. 仅仅复制某些字段(部分结构)
  73. --CREATE TABLE 表名 SELECT 查询列表 FROM 旧表 WHERE 不成立得条件/0;
  74. # 复制authors中的id,au_name,但是没有任何数据
  75. CREATE TABLE copy4
  76. SELECT id,au_Name
  77. FROM author
  78. WHERE 1=2; --筛选条件都不成立,则没有任何数据。或者 筛选条件为0.
  1. # 通用的写法: 为了创建自己的库和表,不确定之前有没有同名库和表
  2. DROP DATABASE IF EXISTS 旧库名;
  3. CREATE DATABASE 新库名;
  4. DROP TABLE IF EXISTS 旧库名;
  5. CREATE TABLE 新表名();
  1. # 1. 创建表dept1【在teat库中】
  2. NAME NULL? TYPE
  3. ID INT(7)
  4. NAME VARCHAR(25)
  5. USE test;
  6. CREATE TABLE dept1(
  7. id INT(7),
  8. NAME VARCHAR(25)
  9. );
  10. # 2. 将表departments[myemployees库中]中的数据插入新表dept2中。【跨库进行表的创建】
  11. --dept2不存在,必须先创建
  12. CREATE TABLE dept2
  13. SELECT departments_id, department_name
  14. FROM myemployees.departments;
  15. # 3. 创建表emp5
  16. CREATE TABLE emp5(
  17. id INT(7),
  18. First_name VARCHAR(25),
  19. Last_jname VARCHAR(25),
  20. Dept_id INT(7)
  21. );
  22. # 4. 将列Last_name的长度增加到50,即修改表的类型
  23. ALTER TABLE emp5 MODIFY COLUMN Last_name VARCHAR(50);
  24. # 5. 根据表employees[myemployees库]创建employees2[test库]
  25. CREATE TABLE employees2 LIKE myemployees.employees;
  26. # 6. 删除表emp5
  27. DROP TABLE IF EXISTS emp5;
  28. # 7. 将表employees2重命名为emp5
  29. ALTER TABLE employees2 RENAME TO emp5;
  30. # 8. 在表dept和emp5中添加新列test_column,并检查所做的操作
  31. ALTER TABLE emp5 ADD COLUMN test_column INT;
  32. ALTER TABLE dept ADD COLUMN test_column INT;
  33. # 9. 直接删除表emp5中的列test_column;
  34. ALTER TABLE emp5 DROP COLUMN test_column;

4.2 数据类型

/*

数值型:

            整形

            小数:

                    定点数

                    浮点数

字符型:

             较短的文本:char、varchar

             较长的文本:text、blob(较长的二进制数据)

日期型:

*/

  1. # 1、整型——Tinyint(1), Smallint(2)
  2. /*
  3. 分类:
  4. tinyint、smallint、mediumint、int/integer、bigint
  5. 1 2 3 4 5
  6. 特点:
  7. ①:可以设置无符号还是有符号,默认是有符号;UNSIGNED是无符号
  8. ②:如果插入的数值超出了范围,汇报out of range异常,并插入临界值
  9. ③:如果不设置长度,会有默认的长度;可以自己设置。
  10. 长度代表了最大宽度,如果不够会用0填充在左边,必须与ZEROFILL搭配使用
  11. */
  12. # 案例1:测试如何设置无符号(负数+正数)和无符号(不能是负数)
  13. CREATE TABLE test_int(
  14. t1 INT(11) ZEROFILL --有符号,可以为负数
  15. t2 INT(10) ZEROFILL UNSIGNED --无符号
  16. );
  17. DESC tab_int;
  18. INSERT INTO tab_int VALUES(-123456);
  19. INSERT INTO tab_int VALUES(-123456,-123456); --报错
  20. INSERT INTO tab_int VALUES(214783648,4294967296); --报错,插入临界值int[]
  21. INSERT INTO tab_int VALUES(123,123);
  1. # 二、浮点型
  2. /*
  3. 浮点数:
  4. 4字节 float(M,D)
  5. 8字节 double(M,D)
  6. 定点数:精确度更高
  7. DEC(M,D)
  8. DECIMAL(M,D)
  9. */
  10. # 特点:
  11. ① M代表整数部位+小数部位个数
  12. D代表小数部位
  13. ②:M和D都可以省略
  14. 如果是decimal,则(M,D)默认为(10,0)
  15. 如果是floatdouble,则会随着插入的数值来决定精度
  16. ③:定点型的精确度较高,即如果要求插入数值的精度较高,如货币运算等则考虑使用decimal定点数
  17. ④:如果超出范围,则报out of range异常。
  18. CREATE TABLE tab_float(
  19. f1 FLOAT(5,2),
  20. f2 DOUBLE(5,2),
  21. f3 DECIMAL(5,2)
  22. );
  23. INSERT INTO tab_float VALUES(123.45,123.45,123.45); --插入原数据
  24. INSERT INTO tab_float VALUES(123.456,123.456,123.456); --四舍五入有:插入123.46,123.46
  25. INSERT INTO tab_float VALUES(123.4,123.4,123.4); --插入123.40,123.40
  26. INSERT INTO tab_float VALUES(1523.4,1523.4,1523.4); --插入999.99
  27. # 测试M和D
  28. CREATE TABLE tab_float(
  29. f1 FLOAT,
  30. f2 DOUBLE,
  31. f3 DECIMAL
  32. );
  33. INSERT INTO tab_float VALUES(123.45,123.45,123.45); --f3异常,DECIMAL默认(10,0)
  34. # 选择原则
  35. /*
  36. 所选择的类型越简单越好,能保存数值的类型越小越好
  37. */
# 三、字符型
  • 较短的文本:

        char(M) :固定长度的字符,M表示最多的字符数,省略M时默认为M=1
        varchar(M):可变长度的字符

  • 较长的文本:

        text
        blob(较大的二进制)

写法M的意思特点空间的耗费效率
charchar(M)最大的字符数,可以省略,默认为1固定长度的字符比较耗费
varcharvarchar(M)最大的字符数,不可以省略可变长度的字符比较节省
  • 其他:

binary和varbinary用于保存较短的二进制
enum用于保存枚举,只能插入枚举出来的
set用于保存集合

  1. CREATE TABLE tab_char(
  2. t1 ENUM('a','b','c','d')
  3. );
  4. INSERT INTO tab_char VALUES('a');
  5. INSERT INTO tab_char VALUES('b');
  6. INSERT INTO tab_char VALUES('c');
  7. INSERT INTO tab_char VALUES('e'); --报错!
  8. SELECT * FROM tab_char;
  1. CREATE TABLE tab_set(
  2. s1 SET('A','B','C','D')
  3. );
  4. INSERT INTO tab_set VALUES('A');
  5. INSERT INTO tab_set VALUES('a,b');
  6. INSERT INTO tab_set VALUES('A','C','D');
  7. SELECT * FROM tab_set;
# 四、日期型
  • 分类:
    date只保存日期
    time 只保存时间
    year只保存年

datetime保存日期+时间
timestamp保存日期+时间:比较容易受时区、语法模式、版本的影响,更能反映当前时区的真实时间。

写法范围时区等的影响
datetime81000-9999不受
timestamp41970-2038
  1. CREATE TABLE tab_date(
  2. t1 DATETIME,
  3. t2 TIMESTAMP
  4. );
  5. INSERT INTO tab_date VALUES(NOW(),NOW());
  6. SELECT * FROM tab_date;
  7. --输出:2022-07-22 12:27:55 2022-07-22 12:27:55
  8. SHOW VARIABLES LIKE 'time_zone'; --查看当前时区
  9. SET time_zone='+9:00'; -- 更改时区
  10. SELECT * FROM tab_date;
  11. ----输出:2022-07-22 12:27:55 2022-07-22 13:27:55

4.3 常见约束

含义:一种限制,用于限制表中的数据,为了保证表中数据的准确和可靠性。

  1. CREATE TABLE 表名(
  2. 字段名 字段类型 约束
  3. );

一、分类:六大约束

  • NOT NULL:非空,用于保证该字段的值不能为空,比如姓名、学号
  • DEFAULT: 默认,用于保证该字段有默认值
  • PRIMARY KEY: 主键,用于保证该字段的值具有唯一性且非空,比如学号、员工编号
  • UNIQUE: 唯一,用于保证该字段的值具有唯一性,可以为null。比如座位号
  • CHECK: 检查约束【mysql中不支持】
  • FOREIGN  KEY: 外键,用于限制两个表的关系
    • 在从表添加外键约束,用于引用主表中某列的值。比如学生表的专业编号,员工表的部门编号,员工表的工种编号

添加约束的时机:

  1. 创建表时
  2. 修改表时

约束的添加分类:

  1. 列级约束:
    1. 六大约束语法上都支持,(除了外键)
    2. 列级约束可以在一个字段上追加多个,中间用空格隔开,没有顺序要求
  2. 表级约束
    1. 除了非空、默认,其他的都支持

一、创建表时添加约束 

  1. CREATE TABLE 表名(
  2. 字段名 字段类型 not null,
  3. 字段名 字段类型 primary key,
  4. 字段名 字段类型 unique,
  5. 字段名 字段类型 default 值,
  6. constraint 约束名 foreign key(字段名) references 主表(被引用列)
  7. );
  1. # 1. 添加列级约束
  2. /*
  3. 语法:直接在字段名和类型后面追加 约束类型即可。
  4. 只支持:默认、非空、主键、唯一
  5. */
  6. CREATE DATABASE students;
  7. USE students;
  8. CREATE TABLE stuinfo(
  9. id INT PRIMARY KEY, #主键:唯一且非空
  10. stuName VARCHAR(20) NOT NULL, #非空
  11. gender CHAR(1) CHECK(gender='男' OR =‘女’), #检查
  12. seat INT UNIQUE, #唯一
  13. age INT DEFAULT 18, #默认
  14. majorID INT
  15. );
  16. DESC stuinfo;
  17. # 查看stuinfo中的所有索引,包括主键、外键、唯一。
  18. SHOW INDEX FROM stuinfo;
  19. # 2. 添加表级约束
  20. /*
  21. 语法:在各个字段最下面
  22. 【constraint 约束名】 约束类型(字段名)
  23. */
  24. DROP TABLE IF EIXSTS stuinfo;
  25. CREATE TABLE stuinfo(
  26. id INT,
  27. id2 INT,
  28. stuname VARCHAR(20),
  29. gender CHAR(1),
  30. seat INT,
  31. seat2 INT,
  32. seat3 INT,
  33. age INT,
  34. majorid INT,
  35. CONSTRAINT pk PRIMARY KEY(id,id2), #两个列组合成一个主键
  36. CONSTRAINT uq UNIQUE(seat), #唯一键可以出现两次
  37. CONSTRAINT uq UNIQUE(seat2,seat3), #两个列组合成的唯一键
  38. CONSTRAINT ck CHECK(gender='男' OR ='女'), #检查
  39. CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id) #外键
  40. );
  1. # 通用的语法:
  2. CREATE DATABASE students;
  3. USE students;
  4. CREATE TABLE stuinfo(
  5. id INT PRIMARY KEY, #主键:唯一且非空
  6. stuName VARCHAR(20) NOT NULL, #非空
  7. gender CHAR(1) CHECK(gender='男' OR =‘女’), #检查
  8. seat INT UNIQUE, #唯一
  9. age INT DEFAULT 18, #默认
  10. majorID INT,
  11. CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)
  12. );

主键和唯一的大对比:

保证唯一性是否允许为空一个表中可以有多少个是否允许组合
主键×至多有一个√,但不推荐
唯一可以有多个√,但不推荐
  • 两个列的组合作为主键:只要不是两个列都相等,就满足唯一性。
  • 两个列的组合作为唯一键

外键:

  1. 要求在从表设置外键关系
  2. 从表的外键列的类型和主表的关联列的类型要求一直或者兼容,名称无要求
  3. 主表的关联列必须时一个key(一般是主键或者唯一)
  4. 插入数据时,先插入主表,再插入从表; 删除数据时,先删除从表,再删除主表

 可以通过以下两种方式来删除主表的记录

  • 级联删除:  用这种方式添加外键时,可以直接删除主表中的行,从表中对应行也删除
  1. ALTER TABLE stuinfo ADD CONSTRAINT fk_stu_major FOREIGN KEY(majorid) REFERENCES major(id) ON DELETE CASCADE;
  2. DELATE FROM major WHERE id=3;
  • 级联置空:删除了主表中的行,从表中的对应内容用NULL换
  1. ALTER TABLE stuinfo ADD CONSTRACT fk_stu_major FOREIGN KEY(majorid) REFERENCES major(id) ON DELETE SET NULL;
  2. DELETE FROM major WHERE id=2;
  1. # stuinfo是从表,major是主表。major中的关联列id必须是主键或者唯一键。
  2. CREATE TABLE major(
  3. id INT UNIQUE/PRIMARY KEY,
  4. majorNAME VARCHAR(20)
  5. );
  6. CREATE TABLE stuinfo(
  7. id INT PRIMARY KEY, #主键:唯一且非空
  8. stuName VARCHAR(20) NOT NULL, #非空
  9. gender CHAR(1) CHECK(gender='男' OR =‘女’), #检查
  10. seat INT UNIQUE, #唯一
  11. age INT DEFAULT 18, #默认
  12. majorID INT,
  13. CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)
  14. );

二、修改表时添加、删除约束

1. 添加列级约束

ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型 新约束;

2. 添加表级约束

ALTER TABLE 表名 ADD  [CONSTRAINT 约束名]   约束类型(字段名)   [外键的引用];

  1. 1、非空
  2. --添加非空
  3. ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型 NOT NULL;
  4. --删除非空
  5. ALTER TABLE 表名 MODITY COLUMN 字段名 字段类型;
  6. 2、默认
  7. --添加默认
  8. ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型 DEFAULT 值;
  9. --删除默认
  10. ALTER TABLE 表名 MODIFY COLUMN 字段名 字段类型;
  11. 3、主键
  12. --添加主键
  13. ALTER TABLE 表名 ADDconstraint 约束名】PRIMARY KEY(字段名);
  14. --删除主键
  15. ALTER TABLE 表名 DROP PRIMARY KEY;
  16. 4、唯一
  17. --添加唯一
  18. ALTER TABLE 表名 ADDconstraint 约束名】 UNIQUE(字段名);
  19. --删除唯一
  20. ALTER TABLE 表名 DROP INDEX;
  21. 5、外键
  22. --添加外键
  23. ALTER TABLE 表名 ADDconstraint 约束名】 FOREIGN KEY(字段名) REFERENCES 主表(被引用列);
  24. --删除外键
  25. ALTER TABLE 表名 DROP FOREIGN KEY 约束名;

  1. 添加非空约束、添加默认约束、添加主键
  1. DROP TABLE IF EXISTS stuinfo;
  2. CREATE TABLE stuinfo(
  3. id INT,
  4. stuName VARCHAR(20),
  5. gender CHAR(1),
  6. seat INT,
  7. age INT,
  8. majorID INT
  9. );
  10. # 1. 非空
  11. --添加非空约束
  12. ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NOT NULL;
  13. --删除非空约束
  14. ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NULL; --或者不写
  15. # 2. 默认
  16. --添加默认约束
  17. ALTER TABLE stuinfo MODIFY COLUMN age INT DEFAULT 18;
  18. # 3. 添加主键--支持列级和表级约束
  19. # ①列级约束
  20. ALTER TABLE stuinfo MODIFY COLUMN id INT PRIMARY KEY;
  21. # ②表级约束
  22. ALTER TABLE stuinfo ADD PRIMARY KEY(id);
  23. # 4. 添加唯一键
  24. # ①列级约束
  25. ALTER TABLE stuinfo seat INT UNIQUE;
  26. # ②表级约束
  27. ALTER TABLE stuinfo ADD UNIQUE(seat);
  28. # 5. 添加外键
  29. ALTER TABLE stuinfo ADD CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id);

    2. 修改表时删除约束

  1. # 1. 删除非空约束
  2. ALTER TABLE stuinfo MODIFY COLUMN stuname VARCHAR(20) NULL; --或者不写null
  3. # 2. 删除默认约束
  4. ALTER TABLE stuinfo MODIFY COLUMN age INT ;
  5. # 3. 删除主键
  6. ALTER TABLE stuinfo MODIFY COLUMN id INT ;
  7. --或者
  8. ALTER TABLE stuinfo DROP PRIMARY KEY;
  9. # 4. 删除唯一
  10. ALTER TABLE stuinfo DROP INDEX seat;【唯一键的名字用SHOW INDEX FROM stuinfo 查是seat】
  11. # 5. 删除外键
  12. ALTER TABLE stuinfo DROP FOREIGN KEY fk_stuinfo_major;

测试 

  1. #1.向表emp2的id列中添加PRIMARY KEY 约束(my_emp_id_pk)
  2. ALTER TABLE emp2 MODIFY COLUMN id INT PRIMARY KEY; --列级约束不支持起名字
  3. ALTER TABLE emp2 ADD CONSTRAINT my_emp_id_pk PRIMARY KEY(id); --表级约束支持起名字
  4. #2.向表dept2的id列中添加PRIMARY KEY 约束(my_dept_id_pk)
  5. ALTER TABLE dept2 MODIFY COLUMN id INT PRIMARY KEY;
  6. ALTER TABLE dept2 ADD CONSTRAINT my_dept_id_pk PRIMARY KEY(id);
  7. #3.向表emp2中添加列dept_id,并在其中定义FOREIGN KEY 约束,与之相关联的列是dept2中的id
  8. ALTER TABLE emp2 ADD COLUMN dept_id INT;
  9. ALTER TABLE emp2 ADD CONSTRAINT fk_emp2_dept2 FOREIGN KEY(dept_id) REFERENCES dept2(id);
位置支持的约束类型是否可以起约束名
列级约束列的后边语法都支持,但外键没有效果不可以
表级约束所有列的下面默认和非空不支持,其他支持可以(主键没有效果)

  • 自增长列:又称为标识列

含义:可以不用手动的插入值,系统提供默认的序列值

特点:标识列有且只有一个,被标识的字段是数值类型,被标识的字段必须是一个key

  • 标识列必须和主键搭配吗?  不一定,但是要求是一个key(主键,唯一,外键,自己定义一个key)
  • 一个表中可以有多少个标识列? 至多一个!
  • 标识列的类型:数值型,INT、FLOAT、DOUBLE
  • 标识列可以通过SET auto_increment_increment=3 设置步长,可以通过 手动插入值,设置起始值。

一、创建表时设置标识列

  1. /*
  2. CREATE TABLE 表(
  3.                 字段名 字段类型 约束 auto_increment
  4. )
  5. */
  6. CREATE TABLE tab_identity(
  7. id INT PRIMARY KEY,
  8. NAME VARCHAR(20)
  9. );
  10. INSERT INTO tab_identity VALUES(1,'John') --数字为标识列,必须唯一不重复,可以用标识列
  11. DROP TABLE IF EXISTS tab_identity;
  12. CREATE TABLE tab_identity(
  13. id INT PRIMARY KEY AUTO_INCREMENT, --添加自增长标识
  14. NAME VARCHAR(20)
  15. );
  16. TRUNCATE TABLE tab_identity;
  17. INSERT INTO tab_identity VALUES(NULL,'John');
  18. INSERT INTO tab_identity(id, NAME) VALUES(NULL,'John');
  19. INSERT INTO tab_identity(NAME) VALUES('John');
  20. SELECT * FROM tab_identity;
  21. --可以设置自增长列的步长
  22. SHOW VARIABLES LIKE '@auto_increment%'; --查看步长
  23. SET auto_increment_increment=3; --设置当前表中的步长为3
  24. INSERT INTO tab_identity VALUES(10,'John'); --更改起始值为10,第一次插入

 二、修改表时设置标识列

  1. /*
  2. ALTER TABLE 表 MODIFY COLUMN 字段名 字段类型 约束 auto_increment;
  3. */
  4. ALTER TABLE tab_identity MODIFY COLUMN id INT PRIMARY KEY AUTO_INCREMENT;

三、修改表时删除标识列

  1. /*
  2. ALTER TABLE 表 MODIFY COLUMN 字段名 字段类型 约束
  3. */
  4. ALTER TABLE tab_identity MODIFY COLUMN id INT PRIMARY KEY;

(五)  TCL语言

Transaction Control Language 事务控制语言

5.1 事务的含义

        一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行。

5.2 事务的特性ACID: ⭐ 面试题

  • 原子性:一个事务不可再分割,要么都执行要么都不执行.
  • 一致性:一个事务执行会使数据从一个一致状态切换到另外一个一致状态.
  • 隔离性:一个事务的执行不受其他事务的干扰.
  • 持久性:一个事务一旦提交,则会永久的改变数据库的数据.
  1. # 案例:转账
  2. # 张三丰 1000
  3. # 郭襄 1000
  4. update 表 set 张三丰的余额=500 where name='张三丰'
  5. # 意外
  6. update 表 set 郭襄的余额=1500 where name='郭襄';
  7. --事务用于这种情况。在这个单元中,每个SQL语句都是相互依赖的,
  8. 整个单独单元作为一个不可分割的整体。
  9. 如果单元中的某一个SQL语句一旦执行失败或者发生错误,整个单元将会回滚,
  10. 所有受到影响的数据将会返回到事务开始以前的状态。
  11. 如果单元中的所有SQL语句均执行成功,则事务被顺利执行。

存储引擎:

  1. 概念: 在mysql中的数据用各种不同的技术存储在文件(或者内存)中.
  2. 通过show engines;来查看mysql支持的存储引擎.
  3. 在mysql中用的最多的存储引擎有: innodb, myisam, memory等. 其中innodb支持事务,而myisam和memory不支持事务.

 5.3 事务的使用

  • 事务的使用
    • 隐式事务:事务没有明显的开启和结束的标记
      比如insert、update、delete语句

      delete fromwhere id =1;
    • 显式事务:事务具有明显的开启和结束的标记
      前提:必须先设置自动提交功能 为 禁用 set autocommit=0; 这个关闭知针对这个十五有效。

  1. # 开启事务的语句
  2. updateset 张三丰的余额=500 where name='张三丰'
  3. updateset 郭襄的余额=1500 where name='郭襄';
  4. # 结束事务的语句;
  • 显示事务的使用
    • 步骤一:开启事务
      • set autocommit=0; 
      • start transaction; 可选的
    • 步骤二:缩写事务中的sql语句(SELECT INSERT UPDATE DELETE),DDL语言没有事务一说
      • 语句1;
      • 语句2;
      • ......
    • 步骤三:结束事务
      • commit; 提交事务
      • rollback;  回滚事务
      • 回滚到指定的地方:rollback to 回滚点名;
  • DELETE和TRUNCATE在事务使用时的区别
    • delete支持回滚
    • truncate不支持
  1. SET autocommit=0
  2. START TRANSACTION;
  3. DELETE FROM account;
  4. ROLLBACK; --回滚成功,撤销了删除操作
  5. SELECT * FROM account;
  6. SET autocommit=0;
  7. START TRANSACTION;
  8. TRUNCATE TABLE account;
  9. ROLLBACK; --回滚失败
  1. # 演示事务的使用步骤
  2. # 开启事务
  3. SET AUTOCOMMIT=0;
  4. START TRANSACTION;
  5. # 编写一组事务的使用语句
  6. UPDATE account SET balance=500 WHERE username='张无忌';
  7. UPDATE account SET balance=500 WHERE username='郭襄'; --只是保存到内存,并没有提交到磁盘文件
  8. # 结束事务
  9. COMMIT; --提交事务:提交到磁盘文件
  10. # 开启事务
  11. SET AUTOCOMMIT=0;
  12. START TRANSACTION;
  13. # 编写一组事务的使用语句
  14. UPDATE account SET balance=1000 WHERE username='张无忌';
  15. UPDATE account SET balance=1000 WHERE username='郭襄'; --只是保存到内存,并没有提交到磁盘文件
  16. # 结束事务
  17. ROLLBACK; --回滚:撤销
  18. SELECT * FROM account;

 5.4 并发事务

  •  多个事务 同时 操作 同一个数据库的相同数据时。即对于同时运行的多个事务,当这些事务访问数据库中的相同数据时,如果没有采取必要的隔离机制,就会导致各种并发问题。
  • 并发问题有哪些?
    • 脏读:一个事务读取了其他事务还没有提交的数据,读到的是其他事务“更新”的数据
    • 不可重复读: T1读取了一个字段,然后T2更新了该字段,之后T1再次读取这个字段,值就不同了。
    • 幻读:T1读取了一个字段,然后T2再该表中插入了一些新的行,之后T1再次读取这个表,就会多处几行。
  • 解决并发问题如何
    • 通过设置隔离级别来解决并发问题
  • 事务的四种隔离级别:
读数据一致性脏读不可重复读幻读
read uncommitted: 读未提交最低级别,只能保证不读取物理上损坏的数据×××
read committed: 读已提交语句级××
repeatable read: 可重复读事务级×
serializable: 串行化 (每次读都需获得表级共享锁,读写相互都会阻塞,性能低下)最高级别,事务级
  1. # mysql中默认 第三个隔离级别
  2. repeatable read
  3. # oracle中默认第二个隔离级别
  4. read committed
  5. # 查看隔离级别
  6. SELECT @@tx_isolation;
  7. SHOW VARIABLES LIKE 'tx_isolation';
  8. # 设置mySQL连接的隔离级别
  9. SET SESSION TRANSACTION ISOLATION LEVEL 隔离级别;
  10. # 设置数据库系统的全局的隔离级别
  11. SET GLOBAL TRANSACTION ISOLATION LEVEL 隔离级别;
  1. #1.演示事务的使用步骤
  2. # 开启事务
  3. SET autocommit=0;
  4. START TRANSACTION;
  5. # 编写一组事务的语句
  6. UPDATE account SET balance = 1000 WHERE username='张无忌';
  7. UPDATE account SET balance = 1000 WHERE username='赵敏';
  8. # 结束事务
  9. ROLLBACK; # commit;
  10. SELECT * FROM account;
  11. #2.演示事务对于deletetruncate的处理的区别
  12. SET autocommit=0;
  13. START TRANSACTION;
  14. DELETE FROM account;
  15. ROLLBACK;
  16. #3.演示savepoint 的使用
  17. SET autocommit=0;
  18. START TRANSACTION;
  19. DELETE FROM account WHERE id=25;
  20. SAVEPOINT a; #设置保存点
  21. DELETE FROM account WHERE id=28;
  22. ROLLBACK TO a; #回滚到保存点:25删除,28没删除
  23. SELECT * FROM account;

(六) 其他 

6.1 视图

含义:虚拟表,和普通的表一样使用

mysql15.1版本出现的新特性,是通过表动态生成的特性。

  1. # 案例:查询姓张的学生名和专业名
  2. SELECT stuname, majorname
  3. FROM stuinfo s
  4. INNER JOIN major m ON s.majorid= m.id
  5. WHERE s.stuname LIKE '张%';
  6. --用视图等价写为
  7. CREATE VIEW v1
  8. AS
  9. SELECT stuname, majorname
  10. FROM stuinfo s
  11. INNER JOIN major m ON s.majorid = m.id;
  12. SELECT * FROM v1 WHERE stuname LIKE '张%';
  • 应用场景:

    • 多个地方用到 相同的查询结果
    • 该查询结果使用的 sql语句比较复杂
  • 好处:

    • sql语句的重用
    • 简化复杂的sql操作,不必知道它的查询细节
    • 保护数据,提高安全性(只提供对方需要的信息)
  • 创建视图
  1. # 创建视图语法
  2. /*
  3. CREATE VIEW my_v1
  4. AS
  5. 查询语句
  6. */
  7. USE myemployees;
  8. # 1.查询姓名中包含a字符的员工名,部门名,工种信息
  9. --视图的创建
  10. CREATE VIEW myv1
  11. AS
  12. SELECT e.last_name, d.department_name, j.job_title
  13. FROM employees e
  14. INNER JOIN departments d ON e.department_id=d.department_id
  15. INNER JOIN jobs j ON j.job_id=e.job_id;
  16. --视图的使用
  17. SELECT * FROM myv1 WHERE last_name LIKE '%a%';
  18. # 2.查询各部门的平均工资级别
  19. CREATE VIEW myv2
  20. AS
  21. SELECT AVG(salary) ag, departmnet_id
  22. FROM employees
  23. GROUP BY department_id;
  24. SELECT myv2.ag, g.grade_level
  25. FROM myv2
  26. INNER JOIN job_grades g
  27. ON myv2.ag BETWEEN g.lowest_sal AND g.highest_sal;
  28. # 3.查询平均工资最低的部门编号
  29. --每个部门的平均工资是myv2
  30. SELECT *
  31. FROM myv2
  32. ORDER BY ag ASC
  33. LIMIT 1;
  34. # 4.查询平均工资最低的部门名和工资
  35. CREATE VIEW myv3
  36. AS
  37. SELECT * FROM myv2 ORDER BY ASC LIMIT 1;
  38. SELECT d.*, myv3.ag
  39. FROM myv3
  40. JOIN departments d ON myv3.department_id=d.department_id
  •  视图的修改
  1. # 方式一:
  2. /*
  3. CREATE OR REPLACE VIEW 视图名 --该视图不存在就创建,存在即修改代替
  4. AS
  5. 查询语句;
  6. */
  7. # 案例:修改myv3
  8. CREATE OR REPLACE VIEW myv3
  9. AS
  10. SELECT AVG(salary), job_id
  11. FROM employees
  12. GROUP BY job_id;
  13. # 方式二:
  14. /*
  15. ALTER VIEW 视图名
  16. AS
  17. 查询语句;
  18. */
  19. ALTER VIEW myv3
  20. AS
  21. SELECT * FROM employees;
  •  删除视图
  1. /*
  2. DROP VIEW 视图名,视图名,...
  3. */
  4. DROP VIEW myv1, myv2, myv3;
  • 查看视图
  1. DESC myv3;
  2. SHOW CREATE VIEW myv3; --在cmd中查看

测试例题:

  1. #1、创建视图emp_v1,要求查询电话号码以011开头的员工姓名和工资、邮箱。
  2. CREATE OR REPLACE VIEW emp_v1
  3. AS
  4. SELECT last_name, salary, email
  5. FROM employees
  6. WHERE phone_number LIKE "011%";
  7. #2 创建视图emp_v2,要求查询部门的最高工资高于12000的部门信息。
  8. CREATE OR REPLACE VIEW emp_v2
  9. AS
  10. SELECT MAX(salary),department_id
  11. FROM employees
  12. GROUP BY department
  13. HAVING emp_v2.MAX(salary) > 12000;
  14. SELECT d.*, emp_v2.MAX(salary)
  15. FROM emp_v2
  16. INNER JOIN departments d ON emp_v2.department_id=d.department_id;
  • 更新试图
  1. # 创建视图myv1
  2. CREATE OR REPLACE VIEW myv1
  3. AS
  4. SELECT last_name, email,
  5. FROM employees;
  6. SELECT * FROM myv1;
  7. # 1.插入数据
  8. INSERT INTO myv1 VALUES('张飞','zf@163.com');
  9. # 2.修改数据
  10. UPDATE myv1 SET last_name='张无忌' WHERE last_name='张飞';
  11. # 删除数据
  12. DELETE FROM myv1 WHERE last_name='张无忌';
  13. --以上都可以修改原始视图
  14. # 为了保护视图,可以增加权限,使之只能只读。

具备以下特点的视图不允许更新

  1. 包含这些关键字的sql语句:分组函数,distinct,group by,having,union,union all
  2. 常量视图
  3. SELECT中包含子查询
  4. join
  5. FROM一个不能更新的视图
  6. WHERE 子句的子查询引用了FROM 子句中的表
  1. # 1.包含这些关键字的sql语句:分组函数,distinct,group by,having,union,union all
  2. CREATE OR REPLACE VIEW myv1
  3. AS
  4. SELECT MAX(salary) m, department_id
  5. FROM employees
  6. GROUP BY department_id;
  7. #更新
  8. UPDATE myv1 SET m=9000 WHERE department_id=10; --更新失败,因为myv1中有group by关键字
  9. # 2. 常量视图
  10. CREATE OR REPLACE VIEW myv2
  11. AS
  12. SELECT 'john' NAME;
  13. #更新
  14. UODATE myv2 SET NAME='lucy'; --更新失败,视图是常量视图
  15. # 3. SELECT中包含子查询
  16. CREATE OR REPLACE VIEW myv3
  17. AS
  18. SELECT (SELECT MAX(salary) FROM employees) 最高工资;
  19. # 更新
  20. UPDATE myv3 SET 最高工资=100000--更新失败,视图中包含子查询
  21. # 4. join
  22. CREATE OR REPLACE VIEW myv4
  23. AS
  24. SELECT last_name, department_name
  25. FROM employees e
  26. JOIN department d
  27. ON e.department_id =d.department_id;
  28. # 更新
  29. UPDATE myv4 SET last_name='张飞' WHERE last_name='Whalen'; --可以更新
  30. # 插入
  31. INSERT INTO myv4 VALUES('陈真','xxxxx'); --不可以插入
  32. # 5.FROM一个不能更新的视图
  33. CREATE OR REPLACE VIEW myv5
  34. AS
  35. SELECT * FROM (myv3);
  36. #更新
  37. UPDATE myv5 SET 最高工资=10000 WHERE department_id=60; --视图不能跟新
  38. # 6.WHERE 子句的子查询引用了FROM 子句中的表
  39. CREATE OR REPLACE VIEW myv6
  40. AS
  41. SELECT last_name, email, salary
  42. FROM employees
  43. WHERE employee_id IN(
  44. SELECT DISTINCT manager_id
  45. FROM employees
  46. WHERE manager_id IS NOT NULL
  47. ); --领导的姓名,邮箱,工资
  48. # 更新
  49. UPDATE myv6 SET salary=10000 WHERE last_name='k_ing'; --更新失败
  • 视图与表的对比
创建语法的关键字是否实际占用物理空间使用
视图CREATE VIEW只保存了逻辑增删改查,一般不能增删改
CREATE TABLE保存了数据增删改查

测试

  1. 1、创建BOOK表
  2. CREATE TABLE BOOK(
  3. bib int primary key,
  4. bname varchar(20) unique not null,
  5. price float default 10,
  6. btypeID int ,
  7. foreign key(btypeID) references bookType(id)
  8. );
  9. 2、开启事务,向表中插入一行数据,并结束
  10. SET autocommit=0;
  11. START transaction;
  12. INSERT INTO BOOK(bib,bname,price,btypeID) VALUES(1,'小李飞刀',100,1)
  13. ROLLBACK;
  14. 3、创建视图,实现查询价格大于100的书名和类型名
  15. CREATE OR REPLACE VIEW myv1
  16. AS
  17. SELECT bname, name
  18. FROM BOOK b
  19. JOIN BOOKTYPE t ON b.btypeID=t.id
  20. WHERE price>100;
  21. 4、修改视图,实现查询价格在90-120之间的书名和价格
  22. CREATE OR REPLACE VIEW
  23. AS
  24. SELECT bname, price
  25. FROM BOOK
  26. WHERE price BETWEEN 90 AND 120;
  27. 5、删除我们所建的视图
  28. DROP VIEW myv1;

6.2 变量

  • 系统变量:
    • 全局变量global
    • 会话变量session

说明:变量时由系统提供的,不是用户定义,属于服务器层面的

  • 自定义变量:
    • 用户变量
    • 局部变量

一、系统变量 

  1. #1、查看所有系统变量
  2. SHOW GLOBAL|【SESSION】ARIABLES; --全局|会话变量
  3. #2、查看满足条件的部分系统变量
  4. SHOW GLOBAL|【SESSION】 VARIABLES LIKE '%char%'; --包含char字符的系统变量
  5. #3、查看指定的某个系统变量的值
  6. SELECT @@【SESSION.】系统变量名; --查会话变量
  7. SELECT @@GLOBAL.系统变量名;
  8. #4、为某个具体的系统变量赋值
  9. --例如设置取消自动提交
  10. --方式一:
  11. SET GLOBAL|【SESSION】 系统变量名 = 值;
  12. --方式二:
  13. SET @@GLOBAL|SESSION .系统变量名 =
  14. #注意:如果是全局变量,则需要加global,如果是会话变量,则需要加session,如果什么都不加就默认是会话变量。

 示例:

  1. # 1》 全局变量
  2. /*
  3. 作用域:服务器每次启动将为所有的全局变量赋初始值,针对于所有会话(连接)有效,但不能跨重启(如果服务器重新启动,之前的赋值效果不存在)
  4. */
  5. # ① 查看所有全局变量
  6. SHOW GLOBAL VARIABLES;
  7. # ② 查看满足条件的部分系统变量
  8. SHOW GLOBAL VARIABLES LIKE '%char%';
  9. # ③ 查看指定的系统变量的值
  10. SELECT @@global.autocommit;
  11. # ④ 为某个系统变量赋值
  12. SET @@global.autocommit=0;
  13. SET GLOBAL autocommit=0;
  14. #2》 会话变量
  15. /*
  16. 作用域:针对于当前会话(连接)有效
  17. */
  18. # ① 查看所有会话变量
  19. SHOW VARIABLES;
  20. SHOW SESSION VARIABLES;
  21. # ② 查看满足条件的部分会话变量
  22. SHOW SESSION VARIABLES LIKE '%char%';
  23. SHOW VARIABLES LIKE '%char%';
  24. # ③ 查看指定的会话变量的值
  25. SELECT @@autocommit;
  26. SELECT @@session.tx_isolation;
  27. # ④ 为某个会话变量赋值
  28. SET @@session.tx_isolation='read-uncommitted';
  29. SET SESSION tx_isolation='read-committed';

 二、自定义变量

  1. # 说明:变量时用户定义的,不是有系统提供的
  2. # 使用步骤:声明-赋值-使用(查看、比较、运算等)
  3. #1》 用户变量
  4. /*
  5. 作用域:针对于当前会话(连接有效),同于会话变量的作用域
  6. 应用在任何地方,也就是begin end 里|外边 都可以。
  7. */
  8. 赋值操作符: =或:=
  9. #① 声明并初始化
  10. SET @用户变量名=值; --或
  11. SET @用户变量名:=值; --或
  12. SELECT @用户变量名:=值;
  13. #② 赋值(更新用户变量的值)
  14. --方式一:通过SET或SELECT
  15. SET @用户变量名=值;
  16. SET @用户变量名:=值;
  17. SELECT @用户变量名:=值;
  18. --方式二:通过SELECT INTO
  19. SELECT 字段 INTO 变量名 FROM 表; --查出来的字段必须是一个值才能赋值给变量,一组值不可以。
  20. #③ 使用(查看用户变量的值)
  21. SELECT @用户变量名;
  22. --案例:
  23. #声明并初始化
  24. SET @name='john';
  25. SET @name=100;
  26. SET @count=1;
  27. #赋值
  28. SELECT COUNT(*) INTO @count
  29. FROM employees; --将员工表的员工数赋值给name这个变量
  30. #查看
  31. SELECT @count;
  32. #2》 局部变量
  33. /*
  34. 作用域:仅仅定义在它的begin end中有效
  35. 应用在begin end中的第一句话!!!
  36. */
  37. #① 声明
  38. DECLARE 变量名 类型;
  39. DECLARE 变量名 类型 DEFAULT 值;
  40. #② 赋值 SETSELECT INTO
  41. SET 局部变量名=值;
  42. SET 局部变量名:=值;
  43. SELECT 字段名 INTO @局部变量名 FROM 表;
  44. #③ 使用
  45. SELECT 局部变量名;
作用域定义和使用的位置语法
用户变量当前会话会话中的任何地方SET必须加@,SELECT不加
局部变量BEGIN END中只能在BEGIN END中的第一句话SET不加@,SELECT加@
  1. # 案例:生命两个变量并复制初始值,求和,并打印
  2. #1. 用户变量
  3. SET @m=1;
  4. SET @n=2;
  5. SET @sum = @m + @n;
  6. SELECT @sum; --输出3
  7. #2.局部变量
  8. DECLARE m INT DEFAULT 1;
  9. DECLARE n INT DEFAULT 2;
  10. DECLARE SUM INT;
  11. SET SUM=m+n;
  12. SELECT SUM; --报错:没有在begin end中使用。

6.3 存储过程和函数

  • 存储过程和函数:类似于java中的方法
  • 好处:
    1、提高代码的重用性
    2、简化操作

一、存储过程

  • 含义:一组预先编译好的SQL语句的集合,理解成批处理语句
  • 好处:
    1. 提高代码的重用性
    2. 简化操作
    3. 减少了编译次数,减少了和数据库服务器的连接次数,提高了效率

1、  创建语法 ⭐

  1. CREATE PROCEDURE 存储过程名(参数列表)
  2. BEGIN
  3. 存储过程体(一组合法的SQL语句)
  4. END
  5. /*
  6. 1、参数列表包含三部分
  7. 参数模式 参数名 参数类型
  8. 举例:
  9. IN stuname varchar(20)
  10. 参数模式:
  11. in:该参数可以作为输入,也就是该参数需要调用方传入值,in可以省略
  12. out:该参数可以作为输出,也就是该参数可以作为返回值
  13. inout:该参数既可以作为输入又可以作为输出,也就是该参数既需要传入值,又可以返回值
  14. 2、如果存储过程体仅仅只有一句话,begin end可以省略
  15. 存储过程体中的每条sql语句的结尾要求必须加分号。
  16. 存储过程的结尾可以使用 delimiter 重新设置
  17. 语法:
  18. delimiter 结束标记
  19. 案例:
  20. delimiter $
  21. */
  22. # 二、调用语法
  23. CALL 存储过程名(实参列表)
  24. #----------------------案例演示-------------------------
  25. # 1.空参列表
  26. # 案例:插入到admin表中五条记录
  27. SELECT * FROM admin;
  28. DELIMITER $
  29. CREATE PROCEDURE myp1()
  30. BEGIN
  31. INSERT INTO admin(username, password)
  32. VALUES('john1','0000'),('lily','0000'),('rose','0000'),('tom','0000'),('peter','0000');
  33. END $
  34. # 调用
  35. CALL myp1()$;
  36. --select * from admin$;
  37. #--------------------------------------------------------------
  38. # 2.创建IN模式参数的存储过程(带传入值)
  39. # 案例1:创建存储过程实现 根据女神名,查询对应的男神信息
  40. --这里的女神名当作参数,需要传入
  41. CREATE PROCEDURE myp2 (IN beautyName VARCHAR(20))
  42. BEGIN
  43. SELECT bo.*
  44. FROM boys bo
  45. RIGHT JOIN beauty b ON bo.id=b.boyfriend_id
  46. WHERE b.name=beautyName
  47. END $
  48. # 调用
  49. CALL myp2('柳岩') $
  50. #案例2:创建存储过程实现,用户是否登录成功
  51. CREATE PROCEDURE mtp3(IN username VARCHAR(20), IN PASSWORD VARCHAR(20))
  52. BEGIN
  53. DECLARE result INT DEFAULT 0; #声明并初始化
  54. SELECT COUNT(*) INTO result --赋值
  55. FROM admin
  56. WHERE admin.username = username
  57. AND PASSWORD = PASSWORD;
  58. SELECT IF (result>0, '成功', '失败'); --使用
  59. END $
  60. CALL mtp3('张飞','8888')$
  61. #--------------------------------------------------------------
  62. #3、创建带OUT 模式的存储过程(带返回值)
  63. # 案例1:根据女神名,返回对应的男神名
  64. CREATE PROCEDURE myp5(IN beautyName VARCHAR(20), OUT boyName VARCHAR(20))
  65. BEGIN
  66. SELECT bo.boyName INTO boyName --赋值
  67. FROM boys bo
  68. INNER JOIN beauty b ON bo.id=b.boyfriend_id
  69. WHERE b.name=beautyName; --查询
  70. END $
  71. #调用
  72. # 定义一个用户变量,可以再存储过程外(begin end外)进行使用
  73. SET @bName$
  74. CALL myp5('小昭', @bName)$
  75. SELECT @bName --查看返回值
  76. #案例2:根据女神们,返回对应的男生名个男神魅力值
  77. CREATE PROCEDURE myp6(IN beautyName VARCHAR(20), OUT boyName VARCHAR(20), OUT userCP INT)
  78. BEGIN
  79. SELECT bo.boyName bo.userCP INTO boyName,userCP --赋值
  80. FROM boys bo
  81. INNER JOIN beauty b ON bo.id=b.boyfriend_id
  82. WHERE b.name=beautyName; --查询
  83. END $
  84. # 调用
  85. CALL myp6('小昭',@bName,@usercp)$
  86. SELECT @bName,@usercp
  87. #--------------------------------------------------------------
  88. #4、创建带INOUT模式参数参数的存储过程
  89. #案例1:传入a和b两个值,最终a和b都翻倍并返回 ——对a,b重新赋值(局部变量的赋值)
  90. CREATE PROCEDURE myp8(INOUT a INT, INOUT b INT)
  91. BEGIN
  92. SET a=a*2;
  93. SET b=b*2; --初始化一个局部变量
  94. END $
  95. #调用
  96. --首先定义两个用户变量
  97. SET @m=10$
  98. SET @n=20$
  99. CALL myp8(@m,@n)
  100. SELECT @m,@n

 案例

  1. # 1、创建存储过程实现传入用户名和密码,插入到admin表中
  2. CREATE PROCEDURE test_pro1(IN username VARCHAR(20), IN loginPWD VARCHAR(20))
  3. BEGIN
  4. INSERT INTO admin(admin.username, PASSWORD)
  5. VALUES(username,loginpwd);
  6. END $
  7. CALL test_pro1('admin','0000')$
  8. SELECT * FROM AFFECTED$
  9. # 2、创建存储过程实现传入女神编号,返回女神名称和女神电话
  10. CREATE PROCEDURE test_pro2(IN id INT, OUT beauty_name VARCHAR(20), OUT phone VARCHAR(20))
  11. BEGIN
  12. SELECT b.NAME,b.pho@nne INTO beauty_name,phone
  13. FROM beauty b
  14. WHERE b.id=id;
  15. END $
  16. CALL test_pro2(1,@n,@p)$
  17. SELECT @n,@p$
  18. # 3、创建存储过程或函数实现传入两个女神的生日,返回大小
  19. CREATE PROCEDURE test_pro3(IN birth1 DATETIME, IN berth2 DATETIME, OUT result INT)
  20. BEGIN
  21. SELECT DATEDIFF(birth1, birth2) INTO result; --birth1>birth2返回正数,< 返回负数 ,相等返回0
  22. END $
  23. CALL teat_pro3('1998-1-1',now(),@result)$
  24. SELECT @result$

    2、 删除存储过程

  1. # 语法:
  2. /*
  3. DROP PROCEDURE 存储过程名
  4. */
  5. DROP PROCEDURE test_pro1;
  6. DROP PROCEDURE test_pro2,test_pro3; --错误,不能多个删除

   3、 查看存储过程的信息

  1. DESC 存储过程名; ×
  2. SHOEW CREATE PROCEDURE 存储过程名;

案例

  1. # 四、创建存储国臣或函数实现传入一个日期,格式化成xxx年xx月xx日并返回
  2. CREATE PROCEDURE test_pro4(IN mydate DATETIME, OUT strDate VARCHAR(20))
  3. BEGIN
  4. SELECT DATE_FORMAT(mydate, '%y年%m月%d日') INTO strDate; --日期转化成字符用:DATE_FORMAT; 字符转化成日期用STR_TO_DATE
  5. END $
  6. CALL test_pro4(NOW(4:), @str) $
  7. SELECT @str $
  8. # 五、创建存储国臣或者函数是实现传入女神名称,返回:女神 and 男神 格式的字符串
  9. --如 传入:小昭
  10. -- 返回: 小昭 and 张无忌
  11. CREATE PROCEDURE teat_pro5(IN beautyName VARCHAR(20), OUT str VARCHAR(50))
  12. BEGIN
  13. SELECT CONCAT(beautyName,'and',boyName) INTO str --赋值
  14. FROM boys bo
  15. RIGHT JOIN beauty b ON b.boyfriend=bo.id
  16. WHERE b.name=beautyName;
  17. END $
  18. CALL teat_pro5('小昭', @str)
  19. SELECT @str $ --成功,但是如果女神没有男朋友,则没有结果,为了出现 ‘女神名 and null’效果:boyName改成IFNULL(boyName, 'null')
  20. CREATE PROCEDURE teat_pro5(IN beautyName VARCHAR(20), OUT str VARCHAR(50))
  21. BEGIN
  22. SELECT CONCAT(beautyName,'and',IFNUKK(boyName,'NULL')) INTO str --赋值
  23. FROM boys bo
  24. RIGHT JOIN beauty b ON b.boyfriend=bo.id
  25. WHERE b.name=beautyName;
  26. END $
  27. CALL teat_pro5('柳岩', @str)
  28. SELECT @str $ --返回:柳岩 and null
  29. # 六、创建存储过程或函数,根据传入的起始索和引条目数,查询beauty表的记录
  30. CREATE PROCEDURE test_pro6(IN startIndex INT,IN size INT)
  31. BEGIN
  32. SELECT * FROM beauty LIMIT startIndex, size;
  33. END $
  34. CALL test_pro6(3,5) $

二、函数

  • 含义:一组预先编译好的SQL语句的集合,理解成批处理语句
  • 好处:
    1. 提高代码的重用性
    2. 简化操作
    3. 减少了编译次数,减少了和数据库服务器的连接次数,提高了效率
  • 区别:
    • 存储过程: 可以有0个返回,也可以有多个返回。适合做批量插入、批量更新
    • 函数: 有且仅有1个返回,适合做处理数据后返回一个结果

1、函数的创建和调用

  1. /*
  2. CREATE FUNCTION 函数名(参数列表) RETURNS 返回类型
  3. BEGIN
  4. 函数体
  5. END
  6. */
  7. # 注意:
  8. # 1.参数列表 包含两部分: 参数名 参数类型
  9. # 2.函数体:肯定会有return语句,否则会报错
  10. # 如果return语句没有放在函数体最后也不会报错,但一般不建议。
  11. return 值;
  12. # 3.函数体中仅有一句话,则可以省略begin end
  13. # 4.使用delimiter语句设置结束标记
  14. delimiter $;

 2、调用语法

  1. # 二、调用语法
  2. SELECT 函数名(参数列表)
  3. #------------案例演示-------------------------------------
  4. # 1.无参有返回的
  5. # 返回公司的员工个数
  6. CREATE FUNCTION myf1() RETURN INT
  7. BEGIN
  8. DECLARE c INT DEFAULT 0; --定义局部变量
  9. SELECT COUNT(*) INTO c --为变量赋值
  10. FROM employees;
  11. RETURN c;
  12. END $
  13. SELECT myf1()$
  14. #=====----------------------------------------------------
  15. # 2. 有参有返回的
  16. # 根据员工名,返回他的工资
  17. CREATE FUNCTION myf2(empName VARCHAR(20)) RETURN DOUBLE
  18. BEGIN
  19. SET @sal=0; --定义一个用户变量
  20. SELECT salary INTO @sal --赋值
  21. FROM employees
  22. WHERE last_name =empName;
  23. RETURN @sal;
  24. END $
  25. SELECT myf2('kochhar') $
  26. # 根据部门名,返回该部门的平均工资
  27. CREATE FUNCTION myf3(deptName VARCHAR(20)) RUTURN DOUBLE
  28. BEGIN
  29. DECLARE sal DOUBLE; --定义一个局部变量
  30. SELECT AVG(salary) INTO sal
  31. FROM employees e
  32. JOIN departments d ON e.department_id=d.department_id
  33. WHERE d.department_name=deptName;
  34. RETURN sal;
  35. END $
  36. SELECT myf3('IT')$

3、查看函数

SHOW CREATE FUNCTION myf3;

4、删除函数

DROP FUNCTION myf3;

案例

  1. #1、创建函数,传入两个float,返回二者之和
  2. CREATE FUNCTION test_fun1(num1 FLOAT, num2 FLOAT)
  3. BEGIN
  4. DECLARE SUM FLOAT DEFAULT 0;
  5. SELECT SUM=num1+num2;
  6. RETURN SUM;
  7. END $
  8. SELECT test_fun1(1,2)$

6.4 流程控制结构

  •  顺序结构:程序从上往下依次进行
  • 分支结构:程序从两条或多条路径中选择一条去执行
  • 循环结构:程序在满足一定条件的基础上,重复执行一段代码

一、分支结构 

  •  IF函数:能实现简单的双分支,可以应用在任何地方
  1. /*
  2. IF (表达式1,表达式2,表达式3)
  3. */
  4. #执行顺序:如果表达式1成立,则IF函数返回表达式2的值,否则返回表达式3的值。
  • CASE结构
    • 情况1:类似于Java中的switch语句,一般用于实现等值判断
  1. CASE 变量|表达式|字段
  2. WHEN 要判断的值 THEN 返回的值1 --不在存储过程和函数中使用:语句1;
  3. WHEN 要判断的值 THEN 返回的值2 --语句2;
  4. ...
  5. ELSE 要返回的值n --语句n;
  6. END CASE;
    • 情况2:类似于Java中的多种IF语句,一般用于实现区间判断
  1. CASE
  2. WHEN 要判断的条件1 THEN 返回的值1 或语句1;
  3. WHEN 要判断的条件2 THEN 返回的值2 或语句2;
  4. ...
  5. ELSE 要返回的值n 或语句n;
  6. END CASE;

特点:

  •   可以作为表达式(值),嵌套在其他语句使用,可以放在任何地方,BEIGN END中或BEGIN END 外边
    • 可以作为单独的语句(语句)去使用,只能放在BEGIN END 中使用
  •    如果WHEN 中的值或者条件成立,则执行对应的THEN中的语句,并且结束CASE;如果都不满足,则执行ELSE中的语句或值。
  •   ELSE可以省略,如果ELSE省略了,并且所有WHEN条件都不满足,则返回NULL
  1. # 案例:创建存储过程,根据传入的成绩,来显示等级,比如传入的成绩:90-100,A;80-90,B;60-80,C;否则,D。
  2. --区间判断:情况2 返回的是值
  3. CREATE PROCEDURE test_case(IN score INT)
  4. BEGIN
  5. CASE
  6. WHEN score >=90 AND score<=100 THEN SELECT 'A';
  7. WHEN score >=80 THEN SELECT 'B';
  8. WHEN score >=60 THEN SELECT 'C';
  9. ELSE 'D';
  10. END CASE;
  11. END $
  12. CALL test_case(95) $
  •  IF结构

功能:实现多重分支

  1. IF 条件1 THEN 语句1;
  2. ELSEIF 条件2 THEN 语句2;
  3. ...
  4. ELSE 语句n】 --else语句可以省略
  5. END IF;
  6. #应用场合:在BEGIN END 中。
  1. # 案例1:根据传入的成绩,来显示等级,比如传入的成绩:90-100为A,80-90为B,60-80为C,否则D
  2. CREATE FUNCTION test_if1(score INT) RETURNS CHAR
  3. BEGIN
  4. IF score>=90 AND score<=100 THEN RETURN 'A'
  5. ELSEIF score>=80 THEN RETURN 'B'
  6. ELSEIF score>=60 THEN RETURN 'C'
  7. ELSE RETURN 'D'
  8. END IF;
  9. END $
  10. SELECT test_if(86)$

二、循环结构

分类:while、loop、repeat

循环控制:iterate类似于continue,继续,结束本次循环,继续下一次循环

                  leave类似于break,跳出循环,结束循环。

  1. 1. while
  2. 【标签:】 WHILE 循环条件 do
  3. 循环体;
  4. END WHILE 【标签】;
  5. # 联想在java中:
  6. -- WHILE(循环条件){
  7. -- 循环体;
  8. -- }
  9. 2. loop
  10. 【标签:】loop
  11. 循环体;
  12. end loop 【标签】;
  13. # 可以用来模拟简单的死循环
  14. 3. repeat
  15. 【标签:】repeat
  16. 循环体;
  17. until 结束循环条件
  18. end repeat【标签】;

案例

  1. # 案例1:批量插入,根据次数插入到admin表中多条记录(没有添加循环控制语句)
  2. -- 没有返回,建PROCEDURE
  3. CREATE PROCEDURE pro_while1(IN insertCount INT)
  4. BEGIN
  5. DECALRE i INT DEFAULT 1;
  6. a:WHILE i<=inserCount DO
  7. INSERT INTO admin(username,PASSWORD) VALUES(CONCAT('Rose',i),'666');
  8. SET i=i+1
  9. END WHILE a;
  10. END $
  11. CALL pro_while1(100)$ --插入100遍
  12. SELECT * FROM admin$
  13. /* JAVA中while使用
  14. int i=1;
  15. while(i<=insertCount){
  16. //插入
  17. i++;
  18. }
  19. */
  20. # ------------------添加leave语句----------------------------------------------
  21. # 案例2:批量插入,根据次数插入到admin表中多条记录,如果次数大于20则停止
  22. TRUNCATE TABLE admin$
  23. DROP PROCEDURE pro_while1$
  24. CREATE PROCEDURE pro_while2(IN insertCount INT)
  25. BEGIN
  26. DECLARE i INT DEFAULT 1;
  27. a: while i<=insertCount DO
  28. INSERT INTO admin(username,password) VALUES(CONCAT('XIAOHUA',i),'9999');
  29. IF i>20 THEN leave a;
  30. END IF;
  31. SET i=i+1;
  32. END while a;
  33. END $
  34. CALL pro_while2(100)$
  35. SELECT * FROM admin$
  36. # -------------------添加iterate语句--------------------------------------------
  37. # 案例3.批量插入,根据次数插入到admin表中多条记录,只插入偶数次
  38. TRUNCATE admin$
  39. DROP PROCEDURE pro_while2$
  40. CREATE PROCEDURE pro_while3(IN insertCount INT)
  41. BEGIN
  42. DECLARE i INT DEFAULT 0;
  43. b:WHILE i<=insertCount
  44. SET i=i+1;
  45. IF MOD(i,2) !=0 THEN iterate b;
  46. END IF;
  47. INSERT INTO admin(username,password) VALUES(CONCAT('lilyna', i),'9090');
  48. END WHILE b;
  49. END $
  50. CALL pro_while3(100)$
  51. SELECT * FROM admin$
  52. --JAVA中写法
  53. /*
  54. int i=0;
  55. while(i<+insertCount){
  56. i++;
  57. if(i%2 !=0){
  58. continue;
  59. }
  60. //插入
  61. }
  62. */
名称语法特点位置
while

label: while 循环条件 do

        循环体

end while label;

先判断后执行begin end中
repeat

label: repeat

        循环体

until 循环结束条件

end repeat label;

先执行后判断begin end中
loop

label: loop

        循环体

end loop label;

没有条件的死循环

用于模拟简单的死循环

begin end中

案例

  1. # 一、已知表stringcontent
  2. # 其中字段:
  3. # id 自增长
  4. # content varchar(20)
  5. # 向该表插入指定个数的,随机字符串
  6. DROP TABLE IF EXISTS stringcontent;
  7. CREATE TABLE srtingcontent(
  8. id INT PRIMARY KEY KEY AUTO_INCREMENT,
  9. content VARCHAR(20)
  10. );
  11. DELIMITER $
  12. CREATE PROCEDURE test_randstr_insert(IN insertCount INT)
  13. BEGIN
  14. DECLARE i INT DEFAULT 1; --定义一个循环变量,表示插入次数
  15. DECLARE str VARCHAR(26) DEFAULT 'abcdefghijklmnopqrstuvwxyz'; #产生一个随机字符串
  16. DECLARE startIndex INT DEFAULT 1; #产生一个随机的正数,代表其实索引1-26
  17. DECLARE len INT DEFAULT 1; #代表截取的字符的长度
  18. WHILE i<=insertCount DO:
  19. SET len=FLOOR(RAND()*(19-startIndex)+1); #产生一个随机的整数,代表截取的长度126-startIndex+1,但是content的长度最长为20,则将26换成20
  20. SET startIndex =FLOOR(RAND()*26+1); #产生一个随机的正数,代表其实索引1-26
  21. INSERT INTO stringcontent(content) VALUES(SUBSTR(str,startIndex,len));
  22. SET I=i+1; #循环变量更新
  23. END WHILE;
  24. END $
  25. CALL test_randstr_insert(10)$
  26. SELECT * FROM stringcontent;

(七) 、窗口函数

function(args)  OVER([PARTITION BY expression][OEDER BY expression [ASC|DESC]][frame])

一、排序函数

  • 例如:rank() over(partition by yy order by xx DESC)
row_number()序号不重复,序号连续形如1,2,3...
rank()序号可以重复,序号不连续形如1,2,2,4...
dense_rank()序号可以重复,序号连续形如1,2,2,3...

案例1:如何写排序代码(不分组排序)

178. 分数排名 - 力扣(LeetCode)

案例2:如何写排序代码(分组排序)

184. 部门工资最高的员工 - 力扣(LeetCode)

利用开窗函数可以取每个部门最高,也可以取前二高,前三高,也可以只取第一第三。

 二、聚合函数配合窗口函数实现滑动窗口计算

常用的聚合函数:

count(col) -返回所有非空值的个数

count(*)

count(字段) -空值不计入 

avg(col) -返回平均值

sum(col) -返回平均值

max(col) -返回最大的值

min(col) -返回最小的值

first(col) -返回第一个记录的值

last(col) -返回最后一个记录的值 

rows模式按物理行来进行划分
range模式按数值逻辑进行划分

{RANGE|ROWS} frame_start   

{RANGE|ROWS} BETWEEN frame_start AND frame_end

        UNBOUNDED PRECEDING  --从头开始

        expression PRECEDING  --往前推expression行

        CURRENT ROW   --当前行

        expression FOLLOWING  --往下推两行

        UNBOUNDED FOLLOWING  --到结束行

默认:BETWEEN unbounded preceding AND CURRENT ROW

  1. # 滚动求近三个月的平均GMV? --往上推两行
  2. SELECT product
  3. ,year_month
  4. ,gmv
  5. ,avg(gmv) over(partition by department,product order by year_month ROWS 2 PRECEDING) AS avg_gmv
  6. FROM product;
  1. # 滚动求 从上架开始到本月 的平均GMV?
  2. --开始行到结束行:默认
  3. SELECT product
  4. ,year_month
  5. ,gmv
  6. ,avg(gmv) over(PARTITION BY department,product ORDER BY year_month ) AS avg_gmv
  7. # 不写,默认是从开始到现在的平均值
  8. FROM product;

三、lag、lead函数求环比

lead(expression,n)返回当前行的后n行
lag(expression,n)返回当前行的前n行
  1. # 求每个产品的GMV的环比涨幅?(这一期-上一期)-1
  2. 例如:lag(gmv,1) --取上一期的gmv值
  3. select product
  4. ,year_month
  5. ,gmv
  6. ,lag(gmv,1) over(PARTITION BY department,product ORDER BY year_month) AS lag_gmv
  7. # 对gmv列进行操作,取当前行的上一行
  8. ,cast(gmv as double) / lag(gmv,1) OVER (PARTITION BY department,product ORDER BY year_month) -1 as growth_rate
  9. #求增长率:当期的值/上一期的值 - 1
  10. # 上一期,当前期都是整形,但是为了让增长率是小数,将分子或者分母转化为double型。
  11. FROM product;
  12. Q&A
  13. 日期不连续怎么办?可以通过join万年历表解决
  14. # 如果数据是以月为单位的,那么如何计算同比涨幅?
  15. 改为lag(gmv,12)

案例:如何求销量top10%的商品信息

precent_rank()(分组内当前行的RANK值-1) / (分组内总行数-1)
cume_dist()小于等于当前值的行数 、 分组内总行数
row_nummber()卡排名范围
  1. select
  2. product
  3. ,precent_rank() over(order by sales desc) as 'percent_rank'
  4. ,cume_dist() over(order by sales) as 'cume_dist'
  5. FROM sku_sales;
  1. # 先对数据进行排序
  2. WITH tmp AS (
  3. SELECT
  4. PRODUCT
  5. ,row_number() over(order by sales desc) as 'rank'
  6. FROM sku_sales )
  7. # 指定阈值rank_bar,在根据上一步的排名和阈值截取数据
  8. SELECT * FROM tmp a
  9. LEFT JOIN(
  10. SELECT ceiling(count(1)*0.1) as rank_bar
  11. FROM sku_sales ) b on 1=1
  12. WHERE 'rank'<=rank_bar;

NTILE(n)函数

功能:将排序分区中的行 划分为特定数量的组。

对于每一行,NTILE()函数返回一个桶号,表示行所属的组。

ntile(n) over([partition by yy] [order by xx] [frame])

  1. SELECT
  2. product
  3. ,ntile(10) over(order by sales desc) as ntile_rank --表示组号。
  4. FROM sku_sales;
  5. # 分成十组,那么第一组就是前百分之10

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/536538
推荐阅读
相关标签
  

闽ICP备14008679号