Mysql的学习笔记
一、数据库概述
1、 概述
- 数据库:Database , 简称DB。是指按照一定格式存储数据的一些文件的组合(数据仓库)
- 数据库管理系统:DataBaseManagement , 简称DBMS,用来管理数据库中的数据的。可以对其中的数据进行增删改查。
- 常见的数据库管理系统:MySQL 、 Oracle、MS SqlSever 、 DB2 、sybase等
- SQL:是一种结构化查询语言通过编写SQL语句,由DBMS负责执行SQL语句,最终来完成数据库中数据的增删改查(相当于编程语言)
- 关系:DBMS -----> 通过执行SQL语句操作数据库中的数据
- CRUD : 增删改查,对应 create 、retrave(查,检索)、update 、 delete ;
2、 安装MySQL
-
免安装版:
- 第一步:去官网下载安装
- (重点)第二步:先解压,然后在mysql下创建一个my.ini文件,
更改my.ini文件里面的两行安装目录,
第二行加上\data,my.ini文件不能多或少一个符号,
在path(环境变量里面)加上mysql路径(/bin)。 - (重点)第三步:进入命令指示符(cmd),
输入mysqld --initialize-insecure --user=mysql,
再输入mysqld -install,
出现Service successfully installed.表示配置完成
启动数据库net start mysql,
输入mysql -u root -p,不用输入密码直接回车
出现mysql>表示配置完成
输入alter user user() identified by “密码”;
输入net stop mysql关闭数据库
-
安装版(msi):
- 注意事项
- 1、端口号:是任何一个软件都会有的,端口号是一个软件的唯一代表。通常和ip地址在一起。ip地址用来定位计算机,port端口号是用来定位计算机上的服务/应用的。在同一台计算机上,端口号不能重复,具有唯一性。 MySQL占用的默认端口号3306
- 2、字符集(字符编码方式):设置MySQL的字符编码方式为UTF - 8
- 3、服务名称:默认是MySQL
- 4、环境变量path
- 5、MySQL超级管理员root名称不变,设置密码
- 6、设计密码的同时,可以激活root账户远程访问。激活后,root账户可以从外地登录访问;不激活则表示root账户只能在本地使用
- 注意事项
3、 MySQL的卸载
-
免安装版:
- 第一步:停止mysql服务
net stop mysql - 第二步:卸载mysql
- 第三步:删除mysql服务
sc delete mysql(服务名称)- 如果服务删除不了,就从注册表删除
win+R:regedit打开注册表
HEKY_LOCAL_MACHINE-SYSTEM-CurrentControlSet-Service
找到mysql服务删除即可
- 如果服务删除不了,就从注册表删除
- 第四步:环境变量删除
- 第一步:停止mysql服务
-
安装版(msi):
- 第一步:双击安装包卸载
- 第二步:删除目录(表层位置,C盘的ProgramDate文件下的MySQL目录一起删掉)
- 第三步:环境变量删除
4、计算机中MySQL的服务
- 流程:计算机右键 — 管理 — 服务和应用程序 — 服务 — 找MySQL服务
- MySQL的服务默认为启动, 默认为自动启动,表示启动操作系统的时候自动启动
Windows 系统中的启动方式
net start MySQL // 启动MySQL服务
net stop MySQL // 关闭MySQL服务
5、如何登录MySQL服务(客户端)
使用bin目录下的mysql.exe命令来连接mysql数据库服务器
-
第一步:启动MySQL服务
-
第二步:mysql -u 用户名称 -p密码 (其中的-u 表示user , -p表示passward)
-
本地登录(显示密码的形式)
C:\Users\张中宇>mysql -u root -p123456 mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.0.18 MySQL Community Server - GPL Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
-
本地登录(隐藏密码的形式)
C:\Users\张中宇>mysql -u root -p Enter password:****** Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 10 Server version: 8.0.18 MySQL Community Server - GPL Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
二、基础命令
1、登录与退出
mysql -u root -p // 本地登录
exit // 退出
\q // 退出
2、MySQL的常用命令
(命令不区分大小写)(mysql不见分号不执行)
show databases; // 查看mysql中有哪些数据库(默认自带4个)
use 数据库名称 ; // 使用某一个数据库
create database 数据库名称 ; // 创建一个新的数据库
show tables ; // 查看数据库下有哪些表
source + 文件路径 // 导入sql文件
select * from 表名 ; // 查看表中的数据
desc(describe) 表名 ; // 不看表的数据,只看表的结构
select version() ; // 查看mysql数据库的版本号
select database(); // 查看当前使用的数据库
\c // 中止命令的输入
三、数据库基本知识
1、表(table)
- 概念:类似于Excel
- 表是数据库中最基本的单元,数据库中以表的是形式表示数据;因为表比较直观
- 任何表都有行和列
- 行(row , 被称为数据或者记录)
- 列(column ,被称为字段)
- 每个字段都有字段名、数据类型(字符串、数字、日期等)、约束(限制性措施)等属性
2 、SQL语句的分类
- 分为DQL、DML、DDL、TCL、DCL
- DQL : 数据查询语言,关键字SELECT
- DML:数据操作语言,对表中的数据进行增删改的 关键字INSECT;DELETE; UPDATE
- DDL:数据定义语言,主要操作的是表的结构,增删改 关键字CREATE、DROP、ALTER
- TCL:事务控制语言:事务提交、事务回滚 关键字COMMIT 、 ROLLBACK
- DCL:数据控制语言:授权、撤销权限 关键字GRANT、REVOKE
3、数据的导入
- source + 文件目录
- 注意:文件的路径一定不要有中文!!!!
mysql> source D:\MySQL\sql-documents\pre\bjpowernode.sql
Query OK, 0 rows affected, 1 warning (0.43 sec)
Query OK, 0 rows affected, 1 warning (0.01 sec)
Query OK, 0 rows affected, 1 warning (0.01 sec)
Query OK, 0 rows affected, 1 warning (0.63 sec)
Query OK, 0 rows affected, 5 warnings (0.38 sec)
Query OK, 0 rows affected (0.14 sec)
Query OK, 1 row affected (0.15 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.02 sec)
Query OK, 0 rows affected (0.02 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 0 rows affected (0.00 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.03 sec)
Query OK, 1 row affected (0.12 sec)
Query OK, 1 row affected (0.02 sec)
Query OK, 0 rows affected (0.00 sec)
mysql> select * from dept;
+--------+------------+----------+
| DEPTNO | DNAME | LOC |
+--------+------------+----------+
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
+--------+------------+----------+
4 rows in set (0.04 sec)
mysql> select * from emp
-> ;
+-------+--------+-----------+------+------------+---------+---------+--------+
| EMPNO | ENAME | JOB | MGR | HIREDATE | SAL | COMM | DEPTNO |
+-------+--------+-----------+------+------------+---------+---------+--------+
| 7369 | SMITH | CLERK | 7902 | 1980-12-17 | 800.00 | NULL | 20 |
| 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 | 1600.00 | 300.00 | 30 |
| 7521 | WARD | SALESMAN | 7698 | 1981-02-22 | 1250.00 | 500.00 | 30 |
| 7566 | JONES | MANAGER | 7839 | 1981-04-02 | 2975.00 | NULL | 20 |
| 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 | 1250.00 | 1400.00 | 30 |
| 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 | 2850.00 | NULL | 30 |
| 7782 | CLARK | MANAGER | 7839 | 1981-06-09 | 2450.00 | NULL | 10 |
| 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 | 3000.00 | NULL | 20 |
| 7839 | KING | PRESIDENT | NULL | 1981-11-17 | 5000.00 | NULL | 10 |
| 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 | 1500.00 | 0.00 | 30 |
| 7876 | ADAMS | CLERK | 7788 | 1987-05-23 | 1100.00 | NULL | 20 |
| 7900 | JAMES | CLERK | 7698 | 1981-12-03 | 950.00 | NULL | 30 |
| 7902 | FORD | ANALYST | 7566 | 1981-12-03 | 3000.00 | NULL | 20 |
| 7934 | MILLER | CLERK | 7782 | 1982-01-23 | 1300.00 | NULL | 10 |
+-------+--------+-----------+------+------------+---------+---------+--------+
14 rows in set (0.00 sec)
mysql> select * from salgrade;
+-------+-------+-------+
| GRADE | LOSAL | HISAL |
+-------+-------+-------+
| 1 | 700 | 1200 |
| 2 | 1201 | 1400 |
| 3 | 1401 | 2000 |
| 4 | 2001 | 3000 |
| 5 | 3001 | 9999 |
+-------+-------+-------+
5 rows in set (0.00 sec)
4、表的结构
-
不看表内容 , 只看表的结构 desc + 表名 ;
-
mysql> desc dept; +--------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------+-------------+------+-----+---------+-------+ | DEPTNO | int(2) | NO | PRI | NULL | | 部门编号 | DNAME | varchar(14) | YES | | NULL | | 部门名称 | LOC | varchar(13) | YES | | NULL | | 地理位置 +--------+-------------+------+-----+---------+-------+ 3 rows in set (0.15 sec) mysql> desc emp ; +----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+-------+ | EMPNO | int(4) | NO | PRI | NULL | | 员工编号 | ENAME | varchar(10) | YES | | NULL | | 员工姓名 | JOB | varchar(9) | YES | | NULL | | 工作岗位 | MGR | int(4) | YES | | NULL | | 上级编号 | HIREDATE | date | YES | | NULL | | 入职日期 | SAL | double(7,2) | YES | | NULL | | 工资 | COMM | double(7,2) | YES | | NULL | | 补助 | DEPTNO | int(2) | YES | | NULL | | 部门编号 +----------+-------------+------+-----+---------+-------+ 8 rows in set (0.00 sec) mysql> desc salgrade ; +-------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+-------+ | GRADE | int(11) | YES | | NULL | | 工资等级 | LOSAL | int(11) | YES | | NULL | | 最低工资 | HISAL | int(11) | YES | | NULL | | 最高工资 +-------+---------+------+-----+---------+-------+ 3 rows in set (0.00 sec)
5、MySQL常用命令
- 详情参见第二部分
四、常用命令
1、DQL语句
1.1 SELECT语句
- 注意:select语句不会更改原表之中的任何内容,只负责检索、查询
- select 后面可以跟字段名(自变量) , 也可以跟字面量/ 字面值(数据)
- 如果select后面跟的是字段名,那么查询字段
- 如果跟的是数据,那么会借助这个表的结构, 形成这个数据表
1.1.1 简单查询
select 字段名 from 表名 ; // 查询一个字段
select 字段名1,字段名2,... from 表名; // 查询多个字段
select * from 表名 ; // 查询所有字段(效率低、可读性差)
select 字段名 as 新字段名 from 表名; // 给查询的列起别名
/*注意:只是将列名的显示改为新的名称,原表不变。select语句不会更改原表之中的任何内容
as可以省略,但只能显示一个字符。
假设起别名是有空格,加上单引号
字符串用单引号标起来(标准),双引号在oracle数据库中无法使用
在列之中的字段可以使用数学表达式
别名是中文,属于字符串,用单引号括起来即可*/
1.1.2 条件查询
- 查询出来符合条件的
- 格式 : select 字段名1 , 字段名2 , 字段名3 … from 表名 where 条件 ;
- 条件查询的条件:
- = \ <>或 != \ < \ <= \ > \ >= \ between…and … \ is null \ and \ or \ in \ not \ like \ % \ _
1、 = 等于
【案例】:查询薪资等于800的员工的姓名和编号
select empno,ename from emp where sal=800 ;
2、<> 或 != 不等于
【案例】:查询薪资不等于800的员工的姓名和编号
select empno,ename from emp where sal<>800 ;
select empno,ename from emp where sal!=800 ;
3、< 小于
【案例】:查询薪资小于2000的员工的姓名与编号
select empno,ename from emp where sal<2000 ;
4、<= 小于等于
【案例】:查询薪资小于3000的员工的姓名与编号
select empno,ename from emp where sal<=3000 ;
5、> 大于
【案例】:查询薪资小于2000的员工的姓名与编号
select empno,ename from emp where sal>4000 ;
6、>= 大于等于
【案例】:查询薪资小于2000的员工的姓名与编号
select empno,ename from emp where sal>=4000 ;
7、between... and... 两个值之间,等同于 >= and <=
注意:使用此语句时必须保证左小右大 , 闭区间,包含两端的值
【案例】:查询薪资小于2000的员工的姓名与编号
select empno,ename from emp where sal between 2000 and 4000 ;
select empno,ename from emp where sal >= 2000 and sal <= 4000 ;
8、is (not) null
【案例】:查询津贴(补助)(不)为null的员工姓名和员工编号
select empno,ename from emp where comm is null;
select empno,ename from emp where comm is not null ;
9、and 并且
【案例】:查询工作岗位是manager并且工资大于2500的员工信息
select * from emp where job = 'manager' and sal > 2500 ;
10、or 或者
【案例】:查询工作岗位是manager或者是salesman的员工信息
select * from emp where job = 'manager' or job = 'salesman';
【注意】:and 和or 同时出现,and 优先级高 , 先执行and。
【语句】: select * from emp where sal > 2500 and deptno = 10 or deptno = 20 ;
表达的意义是工资大于2500并且dept = 10 的人,或者是deptno = 20 的所有人
select * from emp where sal > 2500 and (deptno = 10 or deptno = 20) ;
表达的意义是工资大于2500的人,同时是dept = 10 或者deptno = 20 的所有人
11、(not) in 包含,相当于多个or
【案例】:查询工作岗位是manager或者是salesman的员工信息
select * from emp where job in ('manager', 'salesman');
【注意】:in后面是具体的值,不是区间
12、not not 可以取非 , 主要用在is和in之中
13、like like称为模糊查询,支持% 或者_匹配
% 匹配任意个字符
_ 一个下划线只匹配一个字符
【案例】: 找出姓名中含有'o'的员工信息
select * from emp where ename like '%o%' ;
【案例】:找出姓名中以T结尾的
select * from emp where ename like '%t';
【案例】:找出姓名以k开始的
select * from emp where ename like 'k%';
【案例】:找出姓名第二个字母是A的
select * from emp where ename like '_a%';
【案例】:找出第三个字母是r的
select * from emp where ename like '__r%';
【案例】:找出名字中含有下划线的
select * from emp where ename like '%\_%'; // 反斜杠代表转义, 类似于转义字符
1.1.3 排序
- 格式 : select 字段名1 , 字段名2 , 字段名3 … from 表名 order by 字段名 ;(默认升序排列)
- 格式: select 字段名 from 表名 where 条件 order by 排序方式 ;
【案例】:查询所有员工薪资
select ename , sal from emp order by sal ; // 默认升序
select ename , sal from emp order by sal asc ; // 指定升序排列
select ename , sal from emp order by sal desc ; // 指定降序排列
【案例】:按照员工名字和薪资排列,按照薪资升序排列,如果相同按照姓名升序排列
select ename , sal from emp order by sal asc , ename asc ; // 多字段排序
【案例】:按照查询结果的第二列排列
select ename , sal from emp order by 2 ; // 不建议,因为不健壮
【案例】:找出工资在1250到3000之间的员工信息,按照薪资的降序排列
格式: select 字段名 from 表名 where 条件 order by 排序方式 ;
select ename , sal from emp where sal between 1500 and 3000 order by sal desc ;
1.1.4 数据处理函数
-
数据处理函数又被称为单行处理函数
-
特点:一个输入对应一个输出
函数名 函数功能 lower 转换小写 upper 转换大写 substr 取子串(substr(被截取的字符子串,起始下标,截取的长度)) length 取长度 trim 去空格 str_to_date 将字符串转换成日期 date_format 格式化日期 format 设置千分位 round 四舍五入 rand() 生成随机数 ifnull 可以将null转换成一个具体值
// 单行处理函数
1、lower / upper 转换大小写
【案例】:将员工姓名转换成小写
select lower(ename) from emp ;
2、substr 取子串
【格式】:substr(字符串 , 起始下标 , 截取长度) 起始下标从1开始
【案例】:请找出员工名字第一个字母是A的员工信息
select ename from emp where ename like 'a%' ;
select ename from emp where substr(ename , 1 1) = 'A' ; // 注意是一个等号
3、length
【格式】:length(字段名)
【案例】:求取员工姓名的长度,并更名为enamelength
select length(ename) as enamelength from emp ;
4、trim 去空格
【格式】: select 字符段 from 表名 where 字符段 = trim('传过来的数据');
【案例】: 查询king的数据
select * from emp where ename = trim(' king ');
5、str_to_date 将字符串varchar转换成date 类型
【格式】:str_to_date('字符串日期' , '日期格式') ;
日期格式:年月日时分秒分别为: %Y , %m , %d , %h , %i , %s ;
【案例】:向t_user表中插入一个数据,将字符串类型转换成日期类型
insert into t_user (id , name , birth) values (1 , 'zhangsan' , str_to_date('01-10-1990' , '%d-%m-%Y')) ;
【注意】:如果输入的格式是 %Y-%m-%d , 则转换函数可以省略。
6、date_format 将date类型转换成具有一定格式的varchar字符串类型
【格式】:date_format(字段名 ,'日期格式')
【案例】:查询t_user表中的名字和生日
select name , date_format(birth , '%Y-%m') as birth from t_user ;
7、format 数字格式化
【格式】:format (数字 , ‘格式’);
mysql> select empno , ename , Format(sal , '$999,999') from emp ;
+-------+--------+--------------------------+
| empno | ename | Format(sal , '$999,999') |
+-------+--------+--------------------------+
| 7369 | SMITH | 800 |
| 7499 | ALLEN | 1,600 |
| 7521 | WARD | 1,250 |
| 7566 | JONES | 2,975 |
| 7654 | MARTIN | 1,250 |
| 7698 | BLAKE | 2,850 |
| 7782 | CLARK | 2,450 |
| 7788 | SCOTT | 3,000 |
| 7839 | KING | 5,000 |
| 7844 | TURNER | 1,500 |
| 7876 | ADAMS | 1,100 |
| 7900 | JAMES | 950 |
| 7902 | FORD | 3,000 |
| 7934 | MILLER | 1,300 |
+-------+--------+--------------------------+
14 rows in set, 14 warnings (0.06 sec)
8、round 四舍五入(可以有负数,负数表示相应的整数位数 ; 可以有小数,也是四舍五入保留位数 : 0.4 和 0.6 保留的位数就不一样)
【格式】: select round(值, 保留的小数位数) from 表名 ;
【案例】: 测试 1236.567 的四舍五入值
select round(1236.567 , 0) as result from emp ;
9、rand() 生成随机数 , 也会借助表的结构
【格式】: select rand() as result from emp ;
【案例】:生成 100 以内的 随机数
select round(rand() * 100) as result from emp ;
10、ifnull 可以将null转换成一个具体值
【注意】:在数据库之中,只要有null参与的数学运算 , 结果均为null
【格式】:ifnull(数据 , 被当做的值)
【案例】:将null 改为0 , 计算员工的年薪 , 并重命名为yearsal
select ename , (sal + ifnull(comm , 0)) * 12 as yearsal from emp ;
10、concat 字符串拼接
【案例】:将员工的姓名和员工的编号拼接起来
select concat(ename , empno) from emp ;
11、case.. when... then... when... then...else... end ....
【案例】:当员工的岗位是manager的时候,工资上调10% , 当工作岗位是salesman的时候,工资上调50% (注意:不修改数据库)
select ename , job , sal as oldsal ,(case job when 'manager' then sal*1.1 when 'salesman' then sal * 1.5 else sal end) as newsal from emp order by sal asc , ename desc ;
【案例】:将员工信息以首字母大写的形式展现出来
select concat(upper(substr(ename , 1 , 1)) , lower(substr(ename , 2 , length(ename) - 1)) ) as ename from emp ;
1.1.5 分组函数
-
概念:分组函数又被称为聚合函数、多行处理函数
-
特点:多个输入对应一个输出
函数名 函数功能 count 取得记录数 sum 求和 avg 取平均值 max 取最大的数 min 取最小的数 -
注意:
- 1、分组函数在使用的时候必须先进行分组,然后才能用;如果进行分组,整张表为一个组
- 2、分组函数会自动忽略null , 不需要提前进行处理
- 3、分组函数count(*)和count(字段)的区别
- count(具体字段) : 表示统计该字段下所有不为null的元素的总数
- count(*) : 只要有一行数据,count则++
- 4、分组函数不能够直接使用在where子句中
- 执行顺序:from、 where 、 group by、select 、 order by
- 因为执行where 语句的时候 尚未分组 ,所以会报错
- 5、所用的分组函数可以组合起来一起用
// 多行处理函数
1、count
【案例】:求出员工数量总和
select count(ename) from emp ;
2、sum
3、avg
4、max
5、min
【案例】:同时计算所有员工的工资总和、最高工资、最低工资、平均工资、总数
select sum(sal) , max(sal) , min(sal) , avg(sal) , count(sal) from emp ;
+----------+----------+----------+-------------+------------+
| sum(sal) | max(sal) | min(sal) | avg(sal) | count(sal) |
+----------+----------+----------+-------------+------------+
| 29025.00 | 5000.00 | 800.00 | 2073.214286 | 14 |
+----------+----------+----------+-------------+------------+
1.1.6 分组查询(重点)
- 概念:在实际的应用之中,可能有这样的需求,需要先进行分组,之后对每一个分组进行操作,这个时候就要用到分组查询
- 使用having子句 ,可以对分完组之后的数据进一步过滤 , 不能单独使用,要和group by一起使用 ,并且位置不能改变,不能代替where
- 格式: select 字段名 from 表名 group by …
- 格式 : select 字段名 from 表名 where 条件 group by … order by 排序 ;
【案例】:计算每个工作岗位的工资和
select job , sum(sal) from emp group by job ;
【案例】:计算每个工作的平均薪资
select job , avg(sal) from emp group by job ;
【案例】:计算每个部门的最高薪资
select deptno , max(sal) from emp group by deptno ;
[注意]:在一条select语句后面有 group by ,则在 select 后面只能跟分组的字段,以及分组函数
【案例】:找出每个部门,不同工作岗位的最高工资
select deptno , job , max(sal) from emp group by deptno , job order by deptno asc;
+--------+-----------+----------+
| deptno | job | max(sal) |
+--------+-----------+----------+
| 10 | CLERK | 1300.00 |
| 10 | MANAGER | 2450.00 |
| 10 | PRESIDENT | 5000.00 |
| 20 | ANALYST | 3000.00 |
| 20 | CLERK | 1100.00 |
| 20 | MANAGER | 2975.00 |
| 30 | CLERK | 950.00 |
| 30 | MANAGER | 2850.00 |
| 30 | SALESMAN | 1600.00 |
+--------+-----------+----------+
【案例】:找出每个部门的最高薪资,要求显示最高薪资大于3000
select deptno , max(sal) from emp where sal > 3000 group by deptno ;(效率比下面高)
使用having子句 ,可以对分完组之后的数据进一步过滤, 不能单独使用,要和group by一起使用 ,并且位置不能改变,不能代替where
select deptno , max(sal) from emp group by deptno having max(sal) > 3000 ;(效率低)
【案例】:找出每个部门平均薪资,要求显示最高薪资大于2500
【分析】:因为是平均薪资,无法提前过滤,where失效,用having
select deptno , avg(sal) from emp group by deptno having avg(sal) > 2500 ;
1.1.7 单表查询总结
- 格式: select…from…where…group by…having…order by…
- 执行顺序: from — where — group by ---- having ----- select ----- order by ;
【案例】:找出每个岗位的平均薪资,要求现实平均工资大于1500的,除manager岗位之外,要求按照平均薪资的降序排列
select job , avg(sal) as avgsal from emp where job != 'manager' group by job having avg(sal) > 1500 order by avgsal desc ;
1.1.8 去除重复记录
- 格式:select distinct 字段名 from 表明 ;
- 注意:distinct 只能出现在所有字段的最前面 , 字段有多个时 , 表示联合去重
【案例】:统计工作岗位的数量
select distinct job from emp ;
1.1.9 连接查询(重点)
-
概念:两张表或多张表中联合起来查询数据,从一个表中取一个信息,从另外的表中查询其余信息的查询方式叫做连接查询,联合查询
-
分类:
- 按照年代分类:SQL92 、 SQL99(主要学习)
- 按照表的连接方式分为:内连接、外连接、全连接
- 内连接:等值连接、非等值连接、自连接
- 外连接:左外链接(左连接)、右外链接(右链接)
-
特殊现象:当两张表连接查询,如无限制,会发生笛卡尔积现象
当两张表进行连接查询,没有限制的话,结果是两张表条数的乘积;
// 演示笛卡尔积现象
【案例】:查询两张表的信息
select ename ,empno from emp ,dept ;
+--------+-------+
| ename | empno |
+--------+-------+
| SMITH | 7369 |
| SMITH | 7369 |
| SMITH | 7369 |
| SMITH | 7369 |
| ALLEN | 7499 |
| ALLEN | 7499 |
| ALLEN | 7499 |
| ALLEN | 7499 |
| WARD | 7521 |
| WARD | 7521 |
| WARD | 7521 |
| WARD | 7521 |
| JONES | 7566 |
| JONES | 7566 |
| JONES | 7566 |
| JONES | 7566 |
| MARTIN | 7654 |
| MARTIN | 7654 |
| MARTIN | 7654 |
| MARTIN | 7654 |
| BLAKE | 7698 |
| BLAKE | 7698 |
| BLAKE | 7698 |
| BLAKE | 7698 |
| CLARK | 7782 |
| CLARK | 7782 |
| CLARK | 7782 |
| CLARK | 7782 |
| SCOTT | 7788 |
| SCOTT | 7788 |
| SCOTT | 7788 |
| SCOTT | 7788 |
| KING | 7839 |
| KING | 7839 |
| KING | 7839 |
| KING | 7839 |
| TURNER | 7844 |
| TURNER | 7844 |
| TURNER | 7844 |
| TURNER | 7844 |
| ADAMS | 7876 |
| ADAMS | 7876 |
| ADAMS | 7876 |
| ADAMS | 7876 |
| JAMES | 7900 |
| JAMES | 7900 |
| JAMES | 7900 |
| JAMES | 7900 |
| FORD | 7902 |
| FORD | 7902 |
| FORD | 7902 |
| FORD | 7902 |
| MILLER | 7934 |
| MILLER | 7934 |
| MILLER | 7934 |
| MILLER | 7934 |
+--------+-------+
56 rows in set (0.00 sec)
【分析】:当两张表进行连接查询,没有限制的话,结果是两张表条数的乘积;
工作原理:两张表会从一张表的所有信息分别匹配另一张表的所有信息
【如何避免笛卡尔积现象】:进行表连接时增加条件
select emp.ename , dept.dname from emp , dept where emp.deptno = dept.deptno ;
【注意】:匹配的次数并没有减少,只是显示的记录减少了
【注意2】:进行表查询的时候,注意起别名
select e.ename , d.dname from emp , dept where e.deptno = d.deptno ; // 92语法
【注意3】:表的连接次数越多、效率越低;尽量减少表的连接
- 内连接 (inner) join
- 分类:等值连接、非等值连接、自连接
- 特点:完全匹配上条件的数据可以查出来
// 等值连接
····// 条件是一种等量关系
【案例】:查询每个员工所在部门名称,显示员工名和部门名
select emp.ename , dept.dname from emp , dept where emp.deptno = dept.deptno; //92
select emp.ename , dept.dname from emp join dept on emp.deptno = dept.deptno; //99
//非等值连接
····// 条件不是一种等量关系
【案例】:找出每个员工的薪资等级 , 要求显示员工名,薪资,薪资等级
select e.ename , e.sal , s.grade from emp e join salgrade s on e.sal between s.losal and s.hisal ;
//自连接
····// 一张表看作两张表,起别名加以区分
【案例】:查询员工的上级领导,显示对应地员工名和领导名
select a.ename , b.ename mgrname from emp a join emp b on a.mgr = b.empno ;
【案例2】:查询员工的上级领导,显示对应地员工名和领导名。要求名称首字母大写,其余小写
select concat(upper(substr(a.ename , 1 , 1)) , lower(substr(a.ename , 2 , length(a.ename) - 1)) ) as ename , concat(upper(substr(b.ename , 1 , 1)) , lower(substr(b.ename , 2 , length(b.ename) - 1)) ) as mgrname from emp a join emp b on a.mgr = b.empno;
- 外连接 :left / right(outer)join
- 分类:左外链接(左连接)、右外链接(右链接)
- 左外连接:select … from … left join … on … 其中的left表示join左面的表的信息全部显示
- 右外连接:select … from … right join … on … 其中的right表示join右面的表的信息全部显示
// 左外连接
····// 表示左表为主表,主表的信息会全部显示出
【案例】:查询员工的上级领导,显示对应地员工名和领导名。要求名称首字母大写,其余小写.要求显示所有的名
select concat(upper(substr(a.ename , 1 , 1)) , lower(substr(a.ename , 2 , length(a.ename) - 1)) ) as ename , concat(upper(substr(b.ename , 1 , 1)) , lower(substr(b.ename , 2 , length(b.ename) - 1)) ) as mgrname from emp a left join emp b on a.mgr = b.empno;
// 右外连接
···· // 表示右表为主表,主表的信息会全部显示出
【案例】:查询每个员工所在部门名称,显示员工名和部门名。要求显示所有的部门名
select e.ename , d.deptno from emp e right join d.deptno on e.deptno = d.depto ;
- 多表连接:
- 格式:select… from a join b on … join c on … join d on … ;
【案例】:找出每个部门的员工名称以及工资等级,要求显示员工名、部门名、薪资、薪资等级
select e.ename , d.dname , e.sal , s.grade from emp e left join dept d on e.deptno = d.deptno left join salgrade s on e.sal between s.losal and s.hisal ;
【案例】找出每个员工的员工名称以及工资等级、上级领导,要求显示员工名、领导名、部门名、薪资、薪资等级
select e.ename , a.ename mgrname , d.dname , e.sal , s.grade from emp e left join dept d on e.deptno = d.deptno left join salgrade s on e.sal between s.losal and s.hisal left join emp a on e.mgr = a.empno;
1.1.10 子查询
- 概念:select 语句的嵌套 , 被嵌套的语句称为子查询
- 位置:select 、 from 、 where 后面可以出现
//where字句中的子查询
【案例】:找出比最低工资高的员工姓名和薪资
select ename , sal from emp where sal > (select min(sal) from emp);
//from字句中的子查询
····//from后面的子查询可以将子查询的结果当做一张查询表来看待
【案例】:找出每个岗位的平均工资的薪资等级
select job , a.avgsal , s.grade from (select job , avg(sal) avgsal from emp group by job) as a join salgrade s on a.avgsal between s.losal and hisal ;
//select字句的子查询
····// 只能一次返回一个结果 , 如果多于一条,就会报错
【案例】:找出每个员工的部门名称,要求显示员工名,部门名
select e.ename , d.dname from emp e join dept d on e.deptno = d.deptno ;
select e.ename , (select d.dname from dept d where e.deptno = d.deptno) as dname from emp e ;
1.1.11 union 合并查询结果
- 注意:union 在进行结果集的合并的时候,列数要相同,列的数据类型也相同
【案例】:查询工作岗位是manager和salesman的员工
select ename , job from emp where job in ('manager','salesman');
select ename , job from emp where job = 'manager' union select ename , job from emp where job = 'salesman' ; // 效率更高,因为可以减少匹配的次数
1.1.12 limit(重点)
- 概念:limit 是将查询的一部分取出来,通常使用在分页查询之中
- 分页的作用是提高用户的体验
- 格式:
- 完整用法: limit(startIndex , length) startIndex:起始下标,默认从0开始 ; 没有括号
- 缺省用法:limit + 数字,表示前几;
- 注意:在mysql之中,limit在order by 之后 执行
【案例】:按照薪资降序,输出排名在前5的员工
select ename , sal from emp order by sal desc limit 5;
【案例】:按照薪资降序,输出薪资排名 [3 , 5] 的员工
select ename , sal from emp order by sal desc limit 2 , 3 ;
【案例】:按照薪资降序,输出薪资排名 [5 , 9] 的员工
select ename , sal from emp order by sal desc limit 4 , 5 ;
// 通用分页的写法
每页显示pageSize条数据
第pageNo页 : limit (pageNo - 1) * pageSize , pageSize ;
Java写法:
public static void main(String[] args){
// 用户提交过来的一个页码,以及每页显示的记录条数
int pageNo = 5 ; // 第5页
int pageSize = 10 ; // 每页显示10条
int startIndex = (pageNo - 1) * pageSize ;
String sql = "secelt ... limit" + startIndex + "," + pageSize ;
}
1.2 DQL的总结
- 格式:select … from… where … group by … having … order by … limit …
- 执行顺序:from ---- where ---- group by ---- having ---- select ---- order by ---- limit
2、DDL语句
2.1 CREAT语句
- 用于表的创建
2.1.1 表的创建
- 格式:creat table 表名 (字段名 数据类型 , 字段名2 ,数据类型 , 字段名3 ,数据类型);
- 建议以t_ 或者是 tbl_ 开始,可读性强
- 字段名、表名:见名知意
- 表名和字段名都属于标识符
- 规范:所有的标识符都是小写,单词与单词之间通过下划线进行衔接
【案例】:在test下创建一个学生表,其中性别的默认值设置为“男”
create table t_student(
no int ,
name varchar(32),
sex char(1) default 'm' ,
age int(3),
email varchar(255)
);
【案例】:创建一个用户表
create table t_user(
id int ,
name varchar(32),
birth date ,
create_time datetime
);
// 快速创建表
可以将一个查询结果制成一个新的表
【案例】:将emp复制一份,成为新表,表名为emp2
create table emp2 as select * from emp ;
2.1.2 mysql常见的数据类型
- varchar(0~255):可变长度的字符串,根据实际长度动态分配空间
- char(0~255):定长字符串,效率高,但是使用不当会造成空间浪费
- int(0~11):整型
- bigint:长整型
- float:单精度浮点型
- double:双精度浮点型
- date:短日期类型 , 只包括年月日信息 默认格式:%Y-%m-%d
- datetime:长日期类型,包括年月时时分秒日期 %Y-%m-%d %h:%i:%s
- clob(>=255):字符大对象,最多存储4个G的字符串,比如简介、说明等
- blob:二进制大对象,存储图片、声音、视频等流媒体数据 【插入数据时,用IO流】
2.2 DROP语句
- 格式:
- drop table t_student ; // 当表不存在时,会报错
- drop table if exists t_student 更加健壮
2.3 TRUNCATE语句
- 格式:truncate table 表名
- 特点:物理删除 , 效率高 , 表会被一次截断 ; 不支持回滚
// 快速删除表中的数据 ---- truncate语句
【案例】:删除dept_bak表中的所有数据
truncate table dept_bak ;
当表非常大,上亿条记录时,可以选择使用此方法。
2.4 ALTER语句
- 字段的增删改
- 字段的增加
- 格式:alter table 表名 add 新字段名 新字段数据类型 ;
- 字段的删除
- 格式:alter table 表名 drop 字段名 ;
- 字段的修改
- 对数据类型的修改
- 格式:alter table 表名 modify 字段名 字段名新的数据类型 ;
- 对数据名称的修改
- 格式:alter table 表名 change 字段名 新字段名 新字段名的数据类型 ;
- 对数据类型的修改
- 字段的增加
// 对表的增加
【案例】:向dept_bak中增加一个字段STURCT
alter table dept_bak add STURCT varchar(40);
// 对表的删除
【案例】:删除字段名STRUCT
alter table dept_bak drop STRUCT ;
// 对表的修改
【案例】:将STRUCT字段的数据类型修改为int型
alter table dept_bak modify STRUCT int ;
【案例】:将STRUCT字段的名称修改为S
alter table dept_bak change STRUCT S char(2) ;
- 对约束的增删改
- 增加
- 添加外键约束: alter table 从表 add constraint 约束名称 foreign key 从表(外键字段) references 主表(主键字段);
- 添加主键约束: alter table 表 add constraint 约束名称 primary key 表(主键字段);
- 添加唯一性约束: alter table 表 add constraint 约束名称 unique 表(字段);
- 删除
- 删除外键约束: alter table 表名 drop foreign key 外键(区分大小写) ;
- 删除主键约束: alter table 表名 drop primary key ;
- 删除约束约束: alter table 表名 drop key 约束名称 ;
- 修改
- mysql 对有些约束的修改时不支持,所以我们可以先删除,再添加
- 增加
【案例】:向t_student表中添加约束
alter table t_student add constraint fk_classes_id_1 foreign key(classes_id) references t_classes(classes_id);
alter table t_student add constraint pk primary key(student_id);
alter table t_student add constraint uk unique(email);
【案例】:去除t_student表中的外键、主键、约束的约束
alter table t_student drop foreign key classno;
alter table t_student drop primary key no;
alter table t drop key foreign key;
【案例】:修改t_student中的约束
alter table t_student modify student_name varchar(30) unique;
3、DML语句
3.1 INSERT语句
- insert into 表名(字段名1 , 字段名2 ,字段名3…)values (值1 , 值2 , 值3 …) ;
- insert into 表名 (字段…)values (值1 , 值2…),(值3,值4…),(…);
- 注意:
- 字段名要一一对应
- insert语句执行成功之后,一定会产生一行新的数据
- 字段名可以省略 , 但表示全部都写 ,顺序不能变。
【案例】:向创建出来的学生表中插入五个值
insert into t_student values(1 , 'zhangsan' , 'm' , 20 , '[email protected]');
insert into t_student values(2 , 'lisi' , 'f' , 20 , '[email protected]');
insert into t_student values(3 , 'wangwu' , 'f' , 20 , '[email protected]' );
insert into t_student values(4 , 'zhaoliu' , 'm' , 18 , '[email protected]');
insert into t_student values (5 , 'songqi' , 'm' , 19 , '[email protected]');
mysql> select * from t_student;
+------+----------+------+------+--------------------+
| no | name | sex | age | email |
+------+----------+------+------+--------------------+
| 1 | zhangsan | m | 20 | 21zhangsan@123.com |
| 2 | lisi | f | 20 | 21lisi@123.com |
| 3 | wangwu | f | 20 | 21wangwu@123.com |
| 4 | zhaoliu | m | 18 | 21zhaoliu@123.com |
| 5 | songqi | m | 19 | 21songqi@123.com |
+------+----------+------+------+--------------------+
5 rows in set (0.00 sec)
【学生表的结构】:
mysql> desc t_student;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| no | int(11) | YES | | NULL | |
| name | varchar(32) | YES | | NULL | |
| sex | char(1) | YES | | m | |
| age | int(11) | YES | | NULL | |
| email | varchar(255) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
5 rows in set (0.00 sec)
now() 获取系统当前时间
【案例】:插入李四的信息
insert into t_user (id ,name , birth , create_time) values (2 ,'lisi','2002-10-2',now());
//insert 一次插入多条数据
【案例】:向t_user中一次插入多条数据
insert into t_user values(1 , 'zhangsan' , '2000-10-01' , now()),
(2 , 'lisi' , '2001-01-11' , now()) , (3 , 'wangwu' , '2002-10-02' , now()),
(4 , 'zhaoliu' , '2003-6-8' , now()), (5 , 'songqi' , '2000-12-21' , now());
【案例】:将查询结果插入到一张表之中
create table dept_bak as select * from dept ;
insert into dept_bak select * from dept ;
3.2 DELETE语句
- 格式:delete from 表名 where 条件 ;
- 注意:不加条件表示清空表中的所有数据
- 原理:数据删除,空间不会释放 ----- 可以恢复(rollback)
【案例】:删除表中id = 2 的数据
delete from t_user where id = 2 ;
【案例】:删除t_user表中的所有数据,注意不能删除表的存在。
delete from t_user ; // 效率比较慢
3.3 UPDATE语句
- 格式:update 表名 set 字段名1 = 值1 , 字段2 = 值2 , 字段3 = 值3 … where 条件;
- 注意:如果没有条件,数据会全部更新
【案例】:修改第三条李四的信息为王五,生日为“2001-01-11”
update t_user set name = 'wangwu', birth = '2001-01-11' where id = 3 ;
【案例】:将所有信息的创建日期修改为此时
update t_user set create_time = now();
4、约束
- 概念:约束(constraint)是指在创建表的时候,可以给一些字段加入一些约束
- 作用:保证表中的数据有效
- 常见的约束:非空约束(not null)、唯一性约束(unique)、主键约束(primary key)、外键约束(foreign key)、检查约束(check , mysql不支持,oracle支持)
4.1 非空约束
- not null : 约束的字段不能为空 , 只有列级约束 , 没有表级约束
【案例】:测试非空约束
drop table if exists t_vip ;
create table t_vip(
id int ,
name varchar(255) not null
);
insert into t_vip (id , name) values(1 , 'zhangsan');
insert into t_vip (id , name) values(2 ,'lisi');
insert into t_vip (id) values (3);
// ERROR 1364 (HY000): Field 'name' doesn't have a default value
4.2 唯一性约束
- unique : 约束的字段不能重复,但可以为null (列级约束)
【案例】:测试唯一性约束
drop table if exists t_vip ;
create table t_vip(
id int ,
name varchar(255) unique , // 列级约束
email varchar(255)
);
insert into t_vip (id , name , email) values (1 , 'zhangsan' , '[email protected]');
insert into t_vip (id , name , email) values (2 , 'lisi' , '[email protected]');
insert into t_vip (id , name , email) values (3 , 'wangwu' , '[email protected]');
select * from t_vip ;
insert into t_vip (id , name , email) values (4 , 'wangwu' , '[email protected]');
//ERROR 1062 (23000): Duplicate entry 'wangwu' for key 'name'
insert into t_vip (id) values (4);
insert into t_vip (id) values (5);
select * from t_vip ; // 可以执行
- 多个字段联合唯一性(表级约束)
- 格式:create table 表名 (字段1 , 字段2 … ,unique(字段1 , 字段2));
【案例】:测试两个字段联合唯一性约束
drop table if exists t_vip ;
create table t_vip(
id int ,
name varchar(255) ,
email varchar(255) ,
unique(name , email) // 表级约束
);
insert into t_vip (id , name , email) values (1 , 'zhangsan' , '[email protected]');
insert into t_vip (id , name , email) values (2 , 'zhangsan' , '[email protected]');
select * from t_vip ;
insert into t_vip (id , name , email) values (3 , 'zhangsan' , '[email protected]');
//ERROR 1062 (23000): Duplicate entry '[email protected]' for key 'name'
- 一个字段,被not null 和 unique 联合约束
- 注意:被这两个字段联合约束的字段在desc中会在KEY中显示PRI(primary key) ,会被自动当做主键,成为主键约束 , (mysql专属)
【案例】:测试一个字段的多种联合约束
drop table if exists t_vip ;
create table t_vip (
id int ,
name varchar(255) not null unique
);
desc t_vip ;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(255) | NO | PRI | NULL | | PRI表示主键
| email | varchar(255) | YES | | NULL | |
+-------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
insert into t_vip (id , name) values (1 , 'zhangsan');
insert into t_vip (id , name) values (2 , 'zhangsan'); // 错误
insert into t_vip (id) values (2) ; // 错误
4.3 主键约束
- primary key (pk) :
- 相关概念:
- 主键约束:在主键上加的约束 , 一张表只能添加一个(复合主键也算一个)
- 主键字段:含有主键的字段
- 主键值:主键字段中的每一个值 , 每一行记录的唯一标识 , 类似于身份证号 不能重复、不能为null ,具有唯一性。主键值建议使用int \ bigint \ char 类型,不建议用varchar。主键值一般为数字,一般为定长
- 注意:任意一张表都要有主键 ,如果没有主键,表无效
【案例】:测试主键约束
drop table if exists t_vip ;
create table t_vip (
id int primary key,
name varchar(255)
);
insert into t_vip (id ,name) values (1 , 'zhangsan');
insert into t_vip (id ,name) values (2 , 'lisi');
select * from t_vip ;
insert into t_vip (id ,name) values (2 , 'wangwu')
//ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
insert into t_vip (name) values ('zhaoliu');
//ERROR 1364 (HY000): Field 'id' doesn't have a default value
- 添加联合主键约束 (可以添加联合主键) ------- 复合主键
- 一个字段 ----- 单一主键
- 多个字段 ------ 复合主键 (不建议)
【案例】:展示添加联合主键约束
drop table if exists t_vip ;
create table t_vip (
id int ,
name varchar(255),
email varchar(255),
primary key(id ,name)
);
desc t_vip ;
+-------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(255) | NO | PRI | NULL | |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
insert into t_vip (id , name , email) values (1 , 'zhangsan' , '[email protected]');
insert into t_vip (id , name , email) values (1 , 'lisi' , '[email protected]');
select * from t_vip ; // 可以运行
- 分类:自然主键、业务主键
- 自然主键:主键值是一个自然数,和业务没关系
- 业务主键:主键值和业务紧密关联。例如主键值是银行卡号,为业务主键
- 在开发中,用自然主键使用多一点。(因为主键只要做到不重复就行)
- 机制:自动维护主键值 auto_increment 表示自增(从1 开始);如果第一个数已经赋值,那么赋值的数据会被抛弃,报错。其余正常执行
【案例】:展示自动维护主键值的机制
drop table if exists t_vip ;
create table t_vip (
id int primary key auto_increment ,
name varchar(255)
);
insert into t_vip (id , name) values (2 ,'zhangsan');
insert into t_vip (name) values ('zhangsan');
insert into t_vip (name) values ('zhangsan');
insert into t_vip (name) values ('zhangsan');
insert into t_vip (name) values ('zhangsan');
insert into t_vip (name) values ('zhangsan');
insert into t_vip (name) values ('zhangsan');
insert into t_vip (name) values ('zhangsan');
insert into t_vip (name) values ('zhangsan');
select * from t_vip ;
4.4 外键约束
- foreign key
- 相关概念:
- 外键约束:
- 外键字段:含有外键约束的字段
- 外键值:外键当中的每一个值
- 被引用的表为父表 , 另一个表子子表
- 顺序:
- 创建表的顺序:先父后子
- 删除表的顺序:先子后父
- 删除数据的顺序:先子后父
- 插入数据的顺序:先父后子
- 格式: foreign key (外键字段) references 父表名(父表字段);
- 注意:
- 1、子表外键引用的主表的字段不一定是主表的主键,但至少具有唯一性(unique约束)
- 2、外键值可以为NULL
【案例】:请设计数据库表,来描述“班级和学生”的信息
// 第一种方案:同表存储
缺点:数据冗余,空间浪费
// 第二种方案:异表存储
班级表:t_class 学生表:t_student
drop table if exists t_student ;
drop table if exists t_class ;
create table t_class (
classno int primary key ,
classname varchar(255)
);
create table t_student (
no int primary key auto_increment ,
name varchar(255),
cno int ,
foreign key (cno) references t_class(classno)
);
insert into t_class (classno,classname) values (100 , '山东省潍坊市昌邑一中3年1班');
insert into t_class (classno,classname) values (101 , '山东省潍坊市昌邑一中3年2班');
insert into t_student(name , cno) values ('jack' , 100);
insert into t_student(name , cno) values ('lucy' , 100);
insert into t_student(name , cno) values ('lilei' , 100);
insert into t_student(name , cno) values ('hanmeimei' , 100);
insert into t_student(name , cno) values ('zhangsan' , 101);
insert into t_student(name , cno) values ('lisi' , 101);
insert into t_student(name , cno) values ('wangwu' , 101);
insert into t_student(name , cno) values ('zhaoliu' , 101);
select * from t_class ;
select * from t_student ;
【案例】:通过sql语句添加一条新的信息 (songqi ,102);
insert into t_student (name,cno) values ('songqi' , 102) ;
//ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`t_student`, CONSTRAINT `t_student_ibfk_1` FOREIGN KEY (`cno`) REFERENCES `t_class` (`classno`))
【分析】: 因为在classno之中没有102这个选项,所以在外键约束下的t_student 表中的cno字段无法添加。
// 正确的做法:
insert into t_class (classno,classname) values (102 , '山东省潍坊市昌邑一中3年3班');
insert into t_student (name, cno) values ('songqi' , 102) ;
select * from t_class ;
select * from t_student ;
5、存储引擎
- 概念:mysql中特有的术语,其他数据库中没有。是存储/组织数据的方式,不同的存取引擎
- mysql支持的存储引擎:
- MEMORY
- MRG_MYISAM
- CSV
- FEDERATED
- PERFORMANCE_SCHEMA
- MyISAM
- InnoDB
- BLACKHOLE
- ARCHIVE
- 格式:
- 添加:在建表的时候的‘)’外面使用ENGINE进行指定引擎
【案例】:查看建表语句
show create table t_student ;
+-----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t_student | CREATE TABLE `t_student` (
`no` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`cno` int(11) DEFAULT NULL,
PRIMARY KEY (`no`),
KEY `cno` (`cno`),
CONSTRAINT `t_student_ibfk_1` FOREIGN KEY (`cno`) REFERENCES `t_class` (`classno`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 |
+-----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.04 sec)
其中的ENGINE=InnoDB AUTO_INCREMENT=11 是引擎指定语句,可以在建表的时候进行修改
其中的DEFAULT CHARSET=utf8 是字符编码方式 , 也可以进行修改
mysql默认的存储引擎是InnoDB,默认的字符编码方式是utf8 ;
- 添加存储引擎:
【案例】:创建一个含有主键为id;字段为id、name;引擎为InnoDB 编码方式为utf8的商品表
drop table if exists t_shop ;
create table t_shop (
id int primary key ,
name varchar(255)
) engine = InnoDB default charset = gbk ;
gbk : 可以存储中文 ;
- 查看mysql支持的存储引擎:
【案例】:查看mysql支持的存储引擎
show engines \G ;
mysql> show engines \G;
*************************** 1. row ***************************
Engine: MEMORY
Support: YES
Comment: Hash based, stored in memory, useful for temporary tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 2. row ***************************
Engine: MRG_MYISAM
Support: YES
Comment: Collection of identical MyISAM tables
Transactions: NO
XA: NO
Savepoints: NO
*************************** 3. row ***************************
Engine: CSV
Support: YES
Comment: CSV storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 4. row ***************************
Engine: FEDERATED
Support: NO
Comment: Federated MySQL storage engine
Transactions: NULL
XA: NULL
Savepoints: NULL
*************************** 5. row ***************************
Engine: PERFORMANCE_SCHEMA
Support: YES
Comment: Performance Schema
Transactions: NO
XA: NO
Savepoints: NO
*************************** 6. row ***************************
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
Transactions: NO
XA: NO
Savepoints: NO
*************************** 7. row ***************************
Engine: InnoDB
Support: DEFAULT
Comment: Supports transactions, row-level locking, and foreign keys
Transactions: YES
XA: YES
Savepoints: YES
*************************** 8. row ***************************
Engine: BLACKHOLE
Support: YES
Comment: /dev/null storage engine (anything you write to it disappears)
Transactions: NO
XA: NO
Savepoints: NO
*************************** 9. row ***************************
Engine: ARCHIVE
Support: YES
Comment: Archive storage engine
Transactions: NO
XA: NO
Savepoints: NO
9 rows in set (0.05 sec)
ERROR:
No query specified
- mysql常用的存储引擎:MyISAM、InnoDB、MEMORY
- MyISAM:
- InnoDB:
- MEMORY:
MyISAM 存储引擎是 MySQL 最常用的引擎。
• 它管理的表具有以下特征:
– 使用三个文件表示每个表:
• 格式文件 — 存储表结构的定义(mytable.frm)
• 数据文件 — 存储表行的内容( mytable.MYD)
• 索引文件 — 存储表上索引( mytable.MYI)
– 灵活的 AUTO_INCREMENT 字段处理
– 可被转换为压缩、只读表来节省空间
InnoDB 存储引擎是 MySQL 的缺省引擎。
• 它管理的表具有下列主要特征:
– 每个 InnoDB 表在数据库目录中以.frm 格式文件表示
– InnoDB 表空间 tablespace 被用于存储表的内容
– 提供一组用来记录事务性活动的日志文件
– 用 COMMIT(提交)、 SAVEPOINT 及 ROLLBACK(回滚)支持事务处理
– 提供全 ACID 兼容
– 在 MySQL 服务器崩溃后提供自动恢复
– 多版本( MVCC)和行级锁定
– 支持外键及引用的完整性,包括级联删除和更新
使用 MEMORY 存储引擎的表,其数据存储在内存中,且行的长度固定,这两个特点使得 MEMORY 存储引擎非
常快。
• MEMORY 存储引擎管理的表具有下列特征:
– 在数据库目录内,每个表均以.frm 格式的文件表示。
– 表数据及索引被存储在内存中。
– 表级锁机制。
– 不能包含 TEXT 或 BLOB 字段。
• MEMORY 存储引擎以前被称为 HEAP 引擎。
MyISAM 表最适合于大量的数据读而少量数据更新的混合操作。 MyISAM 表的另一种适用情形是使用压缩的只读表。
• 如果查询中包含较多的数据更新操作,应使用 InnoDB。其行级锁机制和多版本的支持为数据读取和更新的混合 操作提供了良好的并发机制。
• 可使用 MEMORY 存储引擎来存储非永久需要的数据,或者是能够从基于磁盘的表中重新生成的数据。
6、事务
- 概念:transaction ,一个事务就是一个完整的业务逻辑
- 完整的业务逻辑 :不可再分的最小的工作单元
- 只有DML语句和事务有关系 , 因为只有DML语句是操作数据库中的数据的。涉及数据的改动,一定要保证安全。数据安全第一位
- 理解:
- 1、事务需要多条语句协同完成,相当于封装
- 2、一个事务就是多条DML语句同时成功、同时失败
- 3、在事务的执行过程中可以提交、回滚事务
- 提交:清空事务性活动的日志文件(临时文件),将数据彻底持久化到数据库表之中。提交事务标志着事务的结束,并且是全部成功的结束。
- commit 语句
- 回滚:清空事务性活动的日志文件(临时文件),将之前的所有DML操作全部撤销。回滚事务标志着事务的结束,并且是全部失败的结束。
- rollback 语句 , 只能回滚到上一次的提交点
- 提交:清空事务性活动的日志文件(临时文件),将数据彻底持久化到数据库表之中。提交事务标志着事务的结束,并且是全部成功的结束。
- 4、mysql中默认的事务行为 : 自动提交(每执行一次,提交一次)
- 5、关闭自动提交机制 : start transaction ;
【案例】:测试提交事务和回滚事务
drop table if exists dept_bak ;
create table dept_bak(
DEPTNO int(2) not null ,
DNAME varchar(14) ,
LOC varchar(13) ,
primary key (DEPTNO)
);
select * from dept_bak ; // 记为表1
start transaction ;
insert into dept_bak (deptno , dname , loc) values (10 , 'SALES' , 'SHANDONG');
insert into dept_bak (deptno , dname , loc) values (20 , 'SALES' , 'SHANDONG');
insert into dept_bak (deptno , dname , loc) values (30 , 'SALES' , 'SHANDONG');
insert into dept_bak (deptno , dname , loc) values (40 , 'SALES' , 'SHANDONG');
select * from dept_bak ; // 记为表2 , 查看与表1的区别
rollback ;
select * from dept_bak ; // 记为表3 , 查看与表2的区别
insert into dept_bak (deptno , dname , loc) values (10 , 'SALES' , 'SHANDONG');
insert into dept_bak (deptno , dname , loc) values (20 , 'SALES' , 'SHANDONG');
insert into dept_bak (deptno , dname , loc) values (30 , 'SALES' , 'SHANDONG');
insert into dept_bak (deptno , dname , loc) values (40 , 'SALES' , 'SHANDONG');
select * from dept_bak ;
commit;
rollback ;
select * from dept_bak ; // 记为表4 , 查看与表2,3的区别
【结论】:rollback可以回滚到上一次的commit处
无论是提交事务还是回滚事务都会结束事务
-
事务的特性:ACID
- 原子性:说明事务是最小的工作单元,不可再分
- 一致性:在同一个事务中,所有的数据必须一次成功或者同时失败
- 隔离性:A事务和B事务之间具有一定的隔离 (两个事务同时操作同一张表,类似于多线程并发访问同一张表)
- 事务隔离级别:
- 读未提交:read uncommitted ;
- 描述:(最低事务隔离级别)事务A可以读取到事务B未提交的数据
- 存在问题:脏读现象(dirty read)称读到了脏数据(未提交的数据),基本不用
- 读已提交:read committed ;
- 描述:事务A只能读取到事务B提交之后的数据
- 解决问题:解决了脏读现象
- 存在问题:不可重复读取数据
- 数据100% 的真实。是oracle数据库默认的事务隔离级别
- 可重复读:repeatable read ;
-
描述:事务A开启之后,读取到的事务B中的数据都是一致的。即使在A开启后B事务的数据修改并且提交了,事务A读取到的数据还是不变
相当于把表复制了一份,使用复印件进行操作。退出事务之后再次查询,或者开启新的事务,数据才会更新。
-
解决问题:解决了不可重复读取数据的问题
-
存在问题:可能会出现幻影读现象(读取到的数据都是幻象,数据不真实)
-
是 mysql 中默认的事务隔离级别
-
- 读未提交:read uncommitted ;
- 序列化 / 串行化:serializable ;
- 描述:(最高事务隔离级别,效率最低),表示事务排队。类似于synchronized(线程同步)
- 解决问题:解决了所有级别
- 存在问题:效率最低
- 事务隔离级别:
- 持久性:事务最终结束的一个保障
查看隔离级别:select @@transaction_isolation ;;
以下四个是测试数据,测试的时候1 , 2 , 4分别对3。
【案例】:验证read uncommited
drop table if exists t_user ;
create table t_user(
name varchar(255)
);
select @@transaction_isolation ;
set session transaction isolation level read uncommitted ; // 设置全局事务的隔离级别
select @@transaction_isolation ;
use test ;
start trabsaction ;
select * from t_user ;
【案例】:验证read commited
drop table if exists t_user ;
create table t_user(
name varchar(255)
);
select @@transaction_isolation ;
set session transaction isolation level read committed ; // 设置全局事务的隔离级别
select @@transaction_isolation ;
use test ;
start trabsaction ;
select * from t_user ;
insert into t_user (name) values ('zhangsan');
【案例】:验证repeatable read
drop table if exists t_user ;
create table t_user(
name varchar(255)
);
select @@transaction_isolation ;
use test ;
select * from t_user ;
insert into t_user (name) values ('zhangsan');
【案例】:验证serializable
drop table if exists t_user ;
create table t_user(
name varchar(255)
);
select @@transaction_isolation ;
set session transaction isolation level serializable ; // 设置全局事务的隔离级别
select @@transaction_isolation ;
use test ;
select * from t_user ;
insert into t_user (name) values ('zhangsan');
7、索引
-
概念:Index ,索引是在数据库中的字段上添加,是为了提高查询效率而存在的一种机制。一张表的一个字段可以添加一个索引,也可以多个字段联合起来也可以添加索引。相当于目录,是为了缩小扫描范围的一种机制。通过索引检索,效率较高。
-
【注意】:索引需要排序 , 目的是生成区间查询。缩小扫描范围就是扫描区间 和TreeSet数据结构相同(底层是一个自平衡的二叉树);在mysql之中索引是一个B-Tree结构,遵循左小右大原则存放。
-
实现原理:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-baxFsf3Y-1614766137964)(%E6%95%B0%E6%8D%AE%E5%BA%93Mysql.assets/%E7%B4%A2%E5%BC%95%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86-1613111420473.png)]
-
【注意】:
-
1、在所有数据库之中,主键上会自动添加索引;在mysql之中,如果有unique约束的字段也会自动添加索引。
-
2、在任何数据库之中,任何一张表的任何一条记录在硬盘存储上都有一个硬盘的物理存储编号
-
3、在mysql之中,索引是一个单独的对象,不同的引擎以不同的形式存在。
- MyISAM -------- .MYI 文件之中
- InnoDB --------- tablespace
- MEMORY -------- 内存之中
无论存储在何处,索引在mysql之中都以自平衡二叉树 B-Tree 的形式存在
-
-
添加索引的条件:
- 1、数据量庞大
- 2、该字段经常出现在where后面,以条件的形式存在。(字段总会被扫描)
- 3、该字段有很少的DML操作,因为DML语句之后,会重新排序
建议不要随意添加索引,建议通过unique约束的字段或者通过主键查询
-
索引的创建与删除
- 创建:create index 索引名 on 表名(字段);
- 删除:drop index 索引名 on 表名 ;
【案例】:展示索引的创建和删除
// 添加
create index emp_ename_index on emp(ename);
mysql> desc emp ;
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| EMPNO | int(4) | NO | PRI | NULL | |
| ENAME | varchar(10) | YES | MUL | NULL | | 其中的MUL表示索引
| JOB | varchar(9) | YES | | NULL | |
| MGR | int(4) | YES | | NULL | |
| HIREDATE | date | YES | | NULL | |
| SAL | double(7,2) | YES | | NULL | |
| COMM | double(7,2) | YES | | NULL | |
| DEPTNO | int(2) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
8 rows in set (0.00 sec)
// 删除
drop index emp_ename_index on emp ;
- 索引失效:
- 1、模糊查询的时候并且以 ‘%’ 开头的时候,索引失效。所以尽量避免这种情况出现(优化策略)
- 2、使用or的时候,or两面字段至少有一个没有索引 ,索引失效。所以尽量少用or(优化策略)
- 3、使用复合索引的时候,没有使用左侧的列进行查找,索引失效。
- 4、在where当中索引添加了数学运算,索引失效。
- 5、在where当中索引列使用了函数(单行函数,分组函数不能出现在where子句中!),索引失效
- 索引的分类:
- 单一索引
- 复合索引 : create index emp_job_sal_index from emp(job , sal) ;
- 主键索引:
- 唯一性索引
- …
8、视图
-
概念:view , 站在不同的角度去看同一份数据,以文件的形式存在
-
视图对象的创建与删除
- 创建:create view 视图名 as select 字段名 from 表明 ;
- 删除: drop view 视图名 ;
【注意】:只用DQL语句才能用view来创建,可以面向视图对象进行增删改查 , 对视图对象的增删改查会导致原表被操作
-
作用:简化SQL语句
【案例】:展示视图的创建与删除
drop table if exists dept2 ;
create table dept2 select * from dept ;
create view dept2_view as select * from dept2 ;
drop view dept2_view ;
【案例】:面向视图进行创建、更新数据
drop view if exists emp_dept_view ;
create view emp_dept_view as select e.ename , e.sal , d.dname from emp e join dept d on e.deptno = d.deptno ;
select * from emp_dept_view ;
update emp_dept_view set sal = 200 where ename = 'SMITH';
9、DBA常用命令
-
创建用户:create user 用户名 identified by ‘密码’ ;
–可以登录但是只可以看见一个库 information_schema
-
导入导出:
- 导入:source 文件位置
- 导出:mysqldump 数据库名称 > 文件路径 文件名.sql -u 用户名 -p 密码
【案例】展示DBA常用命令
create user zzyyui identified by '20zzy100588A' ;
grant all on *.* to 'zzyyui'@'%' with grant option;
// 回收权限
revoke all on *.* from guest;
//慎用
use mysql;
select * from user;
update user set password = password('') where user = '';
flush privileges;
// 导入导出
mysqldump -u 用户名 -p 数据库名 > 导出的文件名
source D:\ bjpowernode.sql
10 数据库设计范式
-
概念:数据库设计的依据(面试常考)
-
第一范式:任何一张表必须要有主键,每一个字段原子性不可再分;
-
第二范式:建立在第一范式之上,要求所有非主键字段完全依赖主键,不要产生部分依赖;
-
第三范式:建立在第二范式之上,要求所有非主键字段直接依赖主键,不要产生传递依赖。
10.1 第一范式
- 地位:最核心、最重要的范式,所有表的设计都需要满足
- 要求:必须有主键,并且每一个字段原子性不可再分
【案例】:判断是否满足第一范式
学生编号 学生姓名 联系方式
-------------------------------------
1001 张三 zs@gmail.com,1359999999
1002 李四 ls@gmail.com,13699999999
1001 王五 ww@163.net,13488888888
【存在问题】:
1、最后一条记录和第一条重复(不唯一,没有主键)
2、联系方式字段可以再分,不是原子性的
【更改】:
学生编号(pk) 学生姓名 email 联系电话
-------------------------------------------------------------
1001 张三 zs@gmail.com 1359999999
1002 李四 ls@gmail.com 13699999999
1003 王五 ww@163.net 13488888888
10.2 第二范式
- 要求:建立在第一范式之上,要求所有非主键字段完全依赖主键,不要产生部分依赖
- 多对多三张表,关系表两个外键
【案例】:判断是否满足第一范式
学生编号 学生姓名 教师编号 教师姓名
1001 张三 001 王老师
1002 李四 002 赵老师
1003 王五 001 王老师
1001 张三 002 赵老师
确定主键:
学生编号(PK) 教师编号(PK) 学生姓名 教师姓名
1001 001 张三 王老师
1002 002 李四 赵老师
1003 001 王五 王老师
1001 002 张三 赵老师
/**以上虽然确定了主键,但此表会出现大量的冗余,主要涉及到的冗余字段为“学生姓名”和“教师姓名”,出现冗余的
原因在于,学生姓名部分依赖了主键的一个字段学生编号,而没有依赖教师编号,而教师姓名部门依赖了主键的一个
字段教师编号,这就是第二范式部分依赖。***/
解决方案如下:
学生信息表
学生编号( PK) 学生姓名89 / 103
1001 张三
1002 李四
1003 王五
教师信息表
教师编号( PK) 教师姓名
001 王老师
002 赵老师
教师和学生的关系表
学生编号(PK) fk学生表的学生编号 教师编号(PK) fk教师表的教师编号
1001 001
1002 002
1003 001
1001 002
/*如果一个表是单一主键,那么它就复合第二范式,部分依赖和主键有关系
以上是一种典型的“多对多”的设计*/
10.3 第三范式
- 要求:建立在第二范式之上,要求所有非主键字段直接依赖主键,不要产生传递依赖
【案例】:判断是否满足第三范式
学生编号( PK) 学生姓名 班级编号 班级名称
1001 张三 01 一年一班
1002 李四 02 一年二班
1003 王五 03 一年三班
1004 赵六 03 一年三班
/*从上表可以看出,班级名称字段存在冗余,因为班级名称字段没有直接依赖于主键,班级名称字段依赖于班级编号,
班级编号依赖于学生编号,那么这就是传递依赖,解决的办法是将冗余字段单独拿出来建立表,如:*/
学生信息表
学生编号( PK) 学生姓名 班级编号( FK)
1001 张三 01
1002 李四 02
1003 王五 03
1004 赵六 03
班级信息表
班级编号( PK) 班级名称
01 一年一班
02 一年二班
03 一年三班
10.4 三范式总结
-
第一范式: 有主键,具有原子性,字段不可分割
-
第二范式:完全依赖, 没有部分依赖
-
第三范式: 没有传递依赖
-
【注意】:数据库设计尽量遵循三范式,但是还是根据实际情况进行取舍,有时可能会拿冗余换速度,最终用目的要满足客户需求。
-
一对一设计,有两种设计方案:
- 第一种设计方案:主键共享 (较少)
- 第二种设计方案:外键唯一
-
一对多设计:两张表,多 的表加外键
-
多对多设计:三张表,关系表两个外键
【注意】:设计是理论上的,实践和理论都是为了满足客户的需求,有的时候会拿冗余换速度。实际开发中,一切以客户需求为准。
五、34道作业题
5.1 — 5.5
【习题1】取得每个部门最高薪水的人员名称
····// 先取得每个部门的最高薪资作为一张表 , 再和emp连接查询等值等部门的人员名称
select e.ename , a.sal , e.deptno from (select max(sal) sal , deptno from emp group by deptno) as a join emp e on a.sal = e.sal and a.deptno = e.deptno ;
【习题2】哪些人的薪水在部门的平均薪水之上
select distinct e.ename , e.sal from (select avg(sal) as sal , deptno from emp group by deptno) as a join emp e on (e.sal > a.sal and a.deptno = a.deptno);
【习题3】取得部门中(所有人的)平均的薪水等级
select e.deptno , avg(s.grade) from emp e join salgrade s on e.sal between s.losal and s.hisal group by deptno order by deptno asc ;
【习题4】不准用组函数( Max),取得最高薪水(给出两种解决方案)
方案一: select sal from emp order by sal desc limit 1 ;
方案二: select sal from emp where sal not in(select distinct a.sal from emp a join emp b on a.sal < b.sal);
【习题5】取得平均薪水最高的部门的部门编号(至少给出两种解决方案)
方案一: select deptno from emp group by deptno order by avg(sal) desc limit 1 ;
方案二: select deptno from emp group by deptno having avg(sal) = (select max(e.sal) from (select deptno , avg(sal) sal from emp group by deptno) as e);
5.6 — 5.10
【习题6】取得平均薪水最高的部门的部门名称
select d.dname from emp e join dept d on e.deptno = d. deptno group by e.deptno order by avg(e.sal) desc limit 1 ;
【习题7】求平均薪水的等级最低的部门的部门名称
select d.dname from emp e join dept d on e.deptno = d.deptno group by e.deptno order by avg(e.sal) asc limit 1;
【习题8】取得比普通员工(员工代码没有在 mgr 字段上出现的)的最高薪水还要高的领导人姓名
select ename , sal from emp where sal > (select max(sal) from emp where empno not in(select distinct mgr from emp where mgr is not null ));
【习题9】取得薪水最高的前五名员工
select max(sal) from emp order by sal desc limit 5 ;
【习题10】取得薪水最高的第六到第十名员工
select max(sal) from emp order by sal desc limit 5 ,5 ;
5.11 — 5.15
【习题11】取得最后入职的 5 名员工
select ename , hiredate from emp order by hiredate desc limit 5;
【习题12】取得每个薪水等级有多少员工
select s.grade , count(*) from emp e join salgrade s on e.sal between s.losal and s.hisal group by s.grade order by s.grade asc ;
【习题13】面试题
有 3 个表 S(学生表), C(课程表), SC(学生选课表)
S( SNO, SNAME)代表(学号,姓名)95 / 103
C( CNO, CNAME, CTEACHER)代表(课号,课名,教师)
SC( SNO, CNO, SCGRADE)代表(学号,课号,成绩)
问题:
1,找出没选过“黎明”老师的所有学生姓名。
2,列出 2 门以上(含 2 门)不及格学生姓名及平均成绩。
3,即学过 1 号课程又学过 2 号课所有学生的姓名。
请用标准 SQL 语言写出答案,方言也行(请说明是使用什么方言)。
-----------------------------------------------------------------------------
CREATE TABLE SC
(
SNO VARCHAR(200),
CNO VARCHAR(200),
SCGRADE VARCHAR(200)
);
CREATE TABLE S
(
SNO VARCHAR(200 ),
SNAME VARCHAR(200)
);
CREATE TABLE C
(
CNO VARCHAR(200),
CNAME VARCHAR(200),
CTEACHER VARCHAR(200)
);
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '1', '语文', '张');
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '2', '政治', '王');
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '3', '英语', '李');
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '4', '数学', '赵');
INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '5', '物理', '黎明');
commit;
INSERT INTO S ( SNO, SNAME ) VALUES ( '1', '学生 1');
INSERT INTO S ( SNO, SNAME ) VALUES ( '2', '学生 2');
INSERT INTO S ( SNO, SNAME ) VALUES ( '3', '学生 3');
INSERT INTO S ( SNO, SNAME ) VALUES ( '4', '学生 4');
commit;
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '1', '40');
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '2', '30');
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '3', '20');
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '4', '80');
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '5', '60');
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '1', '60');
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '2', '60');
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '3', '60');
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '4', '60');
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '5', '40');
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '3', '1', '60');
INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '3', '3', '80');
commit;
问题 1.找出没选过“黎明”老师的所有学生姓名。
问题 2:列出 2 门以上(含 2 门)不及格学生姓名及平均成绩。
问题 3:即学过 1 号课程又学过 2 号课所有学生的姓名
【习题14】列出所有员工及领导的姓名
select e.ename , ifnull(m.ename,'没有上级') from emp e join emp m on e.mgr = m.empno ;
【习题15】列出受雇日期早于其直接上级的所有员工的编号,姓名,部门名称
select e.empno , e.ename , d.dname from emp e join emp m on e.hiredate < m.hiredate and e.mgr = m.empno join dept d on e.deptno = d.deptno ;
5.16 — 5.20
【习题16】列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门.
select d.dname , e.* from emp e right join dept d on e.deptno = d.deptno order by e.deptno;
【习题17】列出至少有 5 个员工的所有部门
select d.dname , count(*) from emp e join dept d on e.deptno = d.deptno group by e.deptno having count(*) >= 5;
【习题18】列出薪金比"SMITH"多的所有员工信息.
select * from emp where sal > (select sal from emp where ename = 'SMITH');
【习题19】列出所有"CLERK"(办事员)的姓名及其部门名称,部门的人数
select e.ename , d.dname , c.cc from emp e join dept d on e.deptno = d.deptno join (select deptno , count(*) as cc from emp group by deptno) as c on d.deptno = c.deptno where job = 'CLERK' ;
【习题20】列出最低薪金大于 1500 的各种工作及从事此工作的全部雇员人数
select job ,count(*) from emp group by job having min(sal) > 1500 ;
5.21 —5 .25
【习题21】列出在部门"SALES"<销售部>工作的员工的姓名,假定不知道销售部的部门编号
select e.ename from emp e join dept d on d.dname = 'SALES' and e.deptno = d.deptno ;
【习题22】列出薪金高于公司平均薪金的所有员工,所在部门,上级领导,雇员的工资等级
select e.ename '姓名', d.dname '部门名称', ifnull(m.ename , '无') '上级领导', s.grade '工资等级' from emp e join dept d on e.deptno = d.deptno left join emp m on e.mgr = m.empno join salgrade s on e.sal between s.losal and s.hisal where e.sal > (select avg(sal) avgsal from emp) ;
【习题23】列出与"SCOTT"从事相同工作的所有员工及部门名称.
select e.ename , d.dname from emp e join dept d on e.deptno = d.deptno where job = (select job from emp where ename = 'SCOTT') and ename != 'SCOTT';
【习题24】列出薪金等于部门 30 中员工的薪金的其他员工的姓名和薪金
select ename , sal from emp where sal in (select sal from emp where deptno = 30) and deptno != 30 ;
【习题25】列出薪金高于在部门 30 工作的所有员工的薪金的员工姓名和薪金.部门名称.
select e.ename , e.sal , d.dname from emp e join dept d on d.deptno = e.deptno where e.sal > (select max(sal) from emp where deptno = 30) ;
5.26 — 5.30
【习题26】列出在每个部门工作的员工数量,平均工资和平均服务期限.
// 服务期限:从入职到现在服务了多长时间
select d.dname, count(*) , avg(sal) avgsal , avg(now() - e.hiredate ) avgser from emp e join dept d on e.deptno = d.deptno group by e.deptno order by e.deptno asc;
【习题27】出所有员工的姓名、部门名称和工资。
select e.ename , d.dname , e.sal from emp e join dept d on e.deptno = d.deptno ;
【习题28】列出所有部门的详细信息和人数
select d.deptno , d.dname ,d.loc, ifnull(c.cc , '0') '人数' from dept d left join (select deptno , count(*) cc from emp group by deptno) as c on d.deptno = c.deptno ;
【习题29】列出各种工作的最低工资及从事此工作的雇员姓名
select e.empno , e.ename , e.job , e.mgr , e.hiredate , e.sal , e.comm , e.deptno from emp e join (select min(sal) minsal from emp group by job ) as m where e.sal = m.minsal;
【习题30】列出各个部门的 MANAGER(领导)的最低薪金
select deptno , min(sal) from emp where job = 'manager' group by deptno order by deptno asc ;
5.31 — 5.34
【习题31】列出所有员工的年工资,按年薪从低到高排序
select ename , sal*12 as income from emp order by income asc ;
【习题32】求出员工领导的薪水超过 3000 的员工名称与领导名称
select e.ename , m.ename from emp e join emp m on m.sal > 3000 where e.mgr = m.empno;
【习题33】求出部门名称中,带'S'字符的部门员工的工资合计、部门人数
select d.dname , ifnull(sum(sal), '0') as sumsal, count(e.ename) from emp e right join dept d on d.deptno = e.deptno where d.dname like '%S%' group by d.deptno , d.dname ;
【习题34】给任职日期超过 30 年的员工加薪 10%
start transaction ;
update emp set sal = sal*1.1 where timestampdiff(YEAR , hiredate , now()) > 30 ;
rollback ;
六、相关文件
本文前期导入的数据库连接:
https://pan.baidu.com/s/1rbHotfQMnBYWwgbDLCMjNQ 提取码:9wpf