学习中的思考
在 mysql 学习和使用中,我遇到了不少的难题,我觉得我应该形成一套逻辑思考体系,可以让我在初识 mysql 的过程中加入理性思考,从一开始就探求原理,了解所学内容的核心和关键点,做到一叶知秋而不是只见树木不见森林。
- mysql 几种数据类型的底层是如何存储的,不同的 sql 语句对其有何限制?
- 学习 sql 语句时,需要思考:这个 sql 语句的底层是如何实现的,对哪些数据类型起作用,有什么限制,如果这个 sql 语句对单字段可以使用,可否在多字段中使用,在多字段使用的过程中,可否做到只对一个字段起作用或者对多个字段同时起作用?
- 隔离级别是如何实现的?
MySQL 基础
一、为什么要学习数据库
二、数据库的相关概念:
- DB:数据库(database),存储数据的“仓库”,它保存了一系列有组织的数据。
- DBMS:数据库管理系统(Database Management System),数据库是通过 DBMS 创建和操作的容器。
- SQL:结构化查询语言(Structure Query Language),专门用来与数据库通信的语言。
SQL的优点:
- 不是某个特定数据库供应商专有的语言,几乎所有DBMS都支持 SQL 。
- 简单易学。
- 强有力,灵活使用。
三、数据库存储结构的特点:
- 将数据放到表中,表再放到库中。
- 一个数据库可以有多个表,每个表都有一个名字,用来表示自己。表名具有唯一性。
- 表具有一些特定,这些特定定义了数据在表中如何存储,类似 java 中“类”的设计。
- 表由列组成,我们也称为字段。所有表都是由一个或多个列组成的,每一列类似 java 中的“属性”。
- 表中的数据都是按行存储的,每一行类似与 java 中的“对象”。
四、初识MySQL
MySQL产品的介绍
DBMS分为两类:
- 基于共享文件系统的DBMS(Access)
- 基于客户机-服务器的DBMS(MySQL、Oracle、SqlServer)
MySQL产品的安装
MySQL安装
MySQL卸载
- 控制面板卸载
- 安装路径删除 mysql 文件夹 + 删除 C 盘根目录下 ProgramData下 mysql 文件夹;
- 清理注册表:
- A. HKEY_LOCAL_MAACHINE\SYSTEM\ControlSet001\Services\Eventlog\Application\MySQL 目录
- B. HKEY_LOCAL_MAACHINE\SYSTEM\ControlSet002\Services\Eventlog\Application\MySQL 目录
- C. HKEY_LOCAL_MAACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\MySQL 目录
- D. HKEY_LOCAL_MAACHINE\SYSTEM\CurrentControl001\Services\MYSQL 目录
- E. HKEY_LOCAL_MAACHINE\SYSTEM\CurrentControl002\Services\MYSQL 目录
- F. HKEY_LOCAL_MAACHINE\SYSTEM\CurrentControlSet\Services\MYSQL 目录
复制代码
- 删除 C:\Document and Settings\All Users\Application Data\MySQL 目录(隐藏的目录)
MySQL服务的启动和停止
- 方式一:计算机 -> 管理 -> 服务
- 方式二:命令行(管理员)
net start 服务名(启动服务)
net stop 服务名(停止服务)
MySQL服务端的登录和退出
- 方式一:通过 mysql 自带的客户端;只限于 root 用户
- 方式二:通过 windows 自带的客户端
登录:mysql [-h 主机名 -P 端口号] -u 用户名 -p密码
退出:exit 或者 ctrl + c
MySQL常见的命令
- 查看当前所有数据库 show databases;
- 打开指定的库 use 库名;
- 查看当前库的所有表 show tables;
- 查看其它库的所有表 show tables from 库名;
- 查看目前位于哪个库 select database();
- 创建表
- create table 表名(
- 列名 列类型,
- 列名 列类型,
- ......
- );
复制代码
- 方式一:登录到mysql服务器 select version();
- 方式二:没有登录到mysql服务器 mysql --version
MySQL语法规范
- 不区分大小写,但建议关键字大写,表名、列名小写。
- 每条命名最好用分号或 \G、\g 结尾(会格式化输出数据)
- 每条命令根据需要,可以进行缩进或换行。
- 注释
- 单行注释:# 注释文字
- 单行注释:-- 注释文字
- 多行注释:/* 注释文字 */
- 试说出查询语句中涉及到的所有关键字,以及执行先后顺序
- SELECT 查询列表 7
- FROM 表1 别名 第1步
- 连接类型 join 表2 2
- ON 连接条件 3
- WHERE 筛选条件 4
- GROUP BY 分组列表 5
- HAVING 分组后的筛选 6
- ORDER BY 排序列表 8
- LIMIT 偏移,条目数; 9
复制代码 五、DQL(Data Query Language)语言的学习
基础查询
语法:特点:- 1.查询列表可以是:表中的字段、常量值、表达式、函数;
- 2.查询的结果是一个虚拟的表格;查询表中的某个字段
复制代码- > 方式一:
- SELECT `employee_id`,
- `first_name`,
- FROM
- employees;
- > 方式二:
- SELECT * FROM employees;
复制代码- SELECT 100;
- SELECT 'john'; //字符和日期型的常量值必须用单引号,数值型不需要;
复制代码- SELECT VERSION();
- SELECT 函数名(实参列表);
复制代码
- 便于理解;
- 如果要查询的字段有重名的情况,使用别名可以区分开来;
- 如果别名中含有关键词,用 单引号 或者 双引号 将别名括起来;
- 方式一:使用 AS
- SELECT 100%98 AS 结果;
- SELECT last_name AS 姓, first_name AS 名 FROM employees;
- 方式二:使用空格
- SELECT last_name 姓,first_name 名 FROM employees;
复制代码
- 去重 distinct
- DISTINCT 需要放到所有列名的前面。
- DISTINCT 其实对后面所有列名的 组合 进行去重。
- SELECT DISTINCT 字段名 FROM 表名;
- 案例:查询员工表中涉及到的所有部门编号
- SELECT DISTINCT department_id FROM employees;
复制代码- 案例:查询员工名和姓连接成一个字段,并显示为 姓名
- SELECT
- CONCAT(last_name,first_name) AS 姓名
- FROM
- employees;
- 案例:显示出表employee的全部列,各个列之间用逗号连接,列头显示成OUT_PUT
- SELECT
- CONCAT(`first_name`,',',`last_name`,',',`job_id`,',',IFNULL(commission_pct,0)) AS out_put
- FROM
- employees;
复制代码- 功能:判断某字段或表达式是否为null,如果为null,返回指定值,否则返回原本的值
- SELECT ifnull(commissiop_pct,0) from employees;
复制代码 空值参与运算
- 所有运算符或列值遇到 null 值,运算的结果都为 null。
- 在 MySQL 里面, 空值不等于空字符串。一个空字符串的长度是 0,而一个空值的长度是空。而且,在 MySQL 里面,空值是占用空间的。
运算符
算数运算符
mysql 中的加号,只有一个功能:运算符,做加法运算。- SELECT 100+90; 两个操作数都为数值型,则做加法运算
- SELECT '123'+90;只要其中一方为字符型,试图将字符型数值转成数值型,
- 如果转换成功,则继续做加法运算。
- 如果转换失败,则将字符型数值转换成0
- SELECT null+10; 只要其中一方为null,则结果肯定为null
复制代码
- 一个数乘以整数1和除以整数1后仍得原数;
- 个数乘以浮点数1 和除以浮点数1后变成浮点数,数值与原数相等;
- 一个数除以整数后,不管是否能除尽,结果都为一个 浮点数;
- 一个数除以另一个数,除不尽时,结果为一个浮点数,并保留到小数点后4位;
- 乘法和除法的优先级相同,进行先乘后除操作与先除后乘操作,得出的结果相同。
- 在数学运算中,0不能用作除数,在MySQL中,一个数除以0为NULL。
结果的符号与被模数的符号一致。
比较运算符
比较运算符用来对表达式左边的操作数和右边的操作数进行比较,比较的结果为真则返回1,比较的结果为假则返回0,其他情况则返回 NULL。
- 如果等号两边的值一个是整数,另一个是字符串,则MySQL会将字符串转化为数字进行比较。
- 如果等号两边的值、字符串或表达式中有一个为NULL,则比较结果为NULL。
- 使用安全等于运算符时,两边的操作数的值都为NULL时,返回的结果为1而不是NULL,其他返回结果与等于运算符相同。
- LEAST(值1,值2,...,值n):在有两个或多个参数的情况下,返回最小值。当比较值列表中有NULL时,不能判断大小,返回值为NULL。
- GREASTEST:最大值运算符。
逻辑运算符
- 逻辑非运算符 逻辑非(NOT或!)运算符表示当给定的值为0时返回1;当给定的值为非0值时返回0;当给定的值为NULL时,返回NULL。
- 逻辑与运算符 逻辑与(AND或&&)运算符是当给定的所有值均为非0值,并且都不为NULL时,返回1;当给定的一个值或者多个值为0时则返回0;否则返回NULL。
- 逻辑或运算符 逻辑或(OR或||)运算符是当给定的值都不为NULL,并且有任何一个值为非0值时,则返回1,否则返回0;当一个值为NULL,并且另一个值为非0值时,返回1,否则返回NULL;当两个值都为NULL时,返回NULL。
- 逻辑异或运算符 逻辑异或(XOR)运算符是当给定的值中任意一个值为NULL时,则返回NULL;如果两个非NULL的值都是0或者都不等于0时,则返回0;如果一个值为0,另一个值不为0时,则返回1。
- AND 的优先级高于OR。
位运算符
条件查询
<ul>语法:- SELECT
- 查询列表
- FROM
- 表名
- WHERE
- 筛选条件;
复制代码 分类:
<ul>按条件表达式筛选
条件运算符: > < = != >= 12000的员工信息 SELECT * FROM employees WHERE salary>120000;#案例2:查询部分编号不等于90的员工名和部门编号 SELECT last_name, department_id FROM employees; WHERE department_id90;[/code]- #案例1:查询工资>12000的员工信息
- SELECT
- *
- FROM
- employees
- WHERE
- salary>120000;
- #案例2:查询部分编号不等于90的员工名和部门编号
- SELECT
- last_name,
- department_id
- FROM
- employees;
- WHERE
- department_id<>90;
复制代码 常见函数
- #案例一:查询工资在10000到20000之间的员工名、工资以及奖金
- SELECT
- last_name,
- salary,
- commission_pct
- FROM
- employees
- WHERE
- salary >= 10000
- AND
- salary <= 20000
复制代码 单行函数
- 操作数据对象
- 接受参数返回一个结果
- 只对一行进行变换
- 每行返回一个结果
- 可以嵌套
- 参数可以是一列或一个值
字符函数
注意:MySQL中,字符串的位置是从1开始的。
函数作用ASCII(S)返回字符串 S 中的第一个字符的 ASCII 码值CHAR_LENGTH(s)返回字符串s的字符数。作用与CHARACTER_LENGTH(s)相同LENGTH(s)返回字符串s的个数,和字符集有关CONCAT(s1,s2,...,sn)连接s1,s2,......sn 为一个字符串CONACT_WS(x,s1,s2,......,sn)同CONCAT(s1,s2,...)函数,但是每个字符串之间要加上xINSERT(str,idx,len,replacestr)将字符串str从第idx位置开始,len个字符长的子串替换为字符串replacestrREPLACE(str,a,b)用字符串b替换字符串str中所有出现的字符串aUPPER(s) 或 UCASE(s)将字符串s的所有字母都转换成大写字母LOWER(s) 或 LCASE(s)将字符串s的所有字母都转成小写字母LEFT(str,n)返回字符串str最左边的n个字符RIGHT(str,n)返回字符串str最右边的n个字符LPAD(str,len,pad)用字符串pad对str最左边进行填充,直到str的长度为len个字符RPAD(str,len,pad)用字符串pad对str最右边进行填充,直到str的长度为len个字符LTRIM(s)去掉字符串s左侧的空格RTRIM(s)去掉字符串s右侧的空格TRIM(s)去掉字符串s开始与结尾的空格TRIM(s1 FROM s)去掉字符串s开始与结尾的s1TRIM(LEADING s1 FROM s)去掉字符串s开始处的s1TRIM(TRAILING s1 FROM s)去掉字符串s结尾处的s1REPEAT(str,n)返回str重复n次的结果SPACE(n)返回n个空格STRCMP(s1,s2)比较字符串s1,s2的ASCII码值的大小SUBSTR(s,index,len)返回从字符串s的index位置其len个字符,作用与SUBSTING(s,n,len)相同LOCATE(substr,str)返回字符串 substr 在字符串 str 中首次出现的位置,作用与 POSITION(substr IN str)、INSTR(str,substr) 相同。未找到,返回0ELT(m,s1,s2,......,sn)返回指定位置的字符串,如果m=1,则返回s1,如果m=2,则返回s2,如果m=n,则返回snFIELD(s,s1,s2,...,sn)返回字符串s在字符串列表中第一次出现的位置FIND_IN_SET(s1,s2)返回字符串s1在字符串s2中出现的位置。其中,字符串s2是一个以逗号分隔的字符串REVERSE(s)返回s反转后的字符串NULLIF(value1,value2)比较两个字符串,如果value1与value2相等,则返回NULL,否则返回value
- length():获取参数值的字节个数
- #案例1:查询员工名中包含符a的员工信息
- SELECT
- *
- FROM
- employees
- WHERE
- last_name LIKE '%a%';
- #案例2:查询员工名中第三个字符为e,第五个字符为a的员工名和工资
- SELECT
- last_name,
- salary,
- FROM
- employees
- WHERE
- last_name LIKE '__e_a%';
- #案例3:查询员工名中第二个字符为_的员工名
- SELECT
- last_name
- FROM
- employees
- WHERE
- last_name LIKE '_\_%'; 或者 last_name LIKE '_$_%' ESCAPE '$';
复制代码 - concat():拼接字符串
- 案例1:查询员工编号在100到120之间的员工信息
- SELECT
- *
- FROM
- employees
- WHERE
- employee_id BETWEEN 100 AND 120;
复制代码 - upper()、lower()
- substr()、substring():
注意:索引从1开始- 案例:查询员工的工种编号是 IT_PROG、AD_VP、AD_PRES中的一个员工名和工种编号。
- SELECT
- last_name,
- job_id
- FROM
- employees
- WHERE
- job_id IN ('IT_PROT','AD_VP','AD_PRES');
复制代码 - instr():返回字串第一次出现的索引,如果找不到返回0
- trim():
- 案例1:查询没有奖金的员工名和奖金率
- SELECT
- last_name,
- commission_pct
- FROM
- employees
- WHERE
- commission_pct IS NULL; IS NOT NULL
复制代码 - lpad():用指定的字符实现左填充指定长度
- 案例1:查询没有奖金的员工名和奖金率
- SELECT
- last_name,
- commision_pct
- FROM
- employees
- WHERE
- commission_pct <=> NULL;
- 案例2:查询工资为12000的员工名和奖金率
- SELECT
- last_name,
- commision_pct
- FROM
- employees
- WHERE
- salary <=> 12000;
复制代码 - rpad():用指定的字符实现右填充指定长度
- SELECT 查询列表
- FROM 表
- [WHERE 筛选条件]
- order by 排序列表 [asc/desc]
复制代码 - replace():替换
数学函数
- round():四舍五入
- #案例1:查询愚弄信息,要求工资从高到低排序
- SELECT * FROM employees
- ORDER BY salary DESC;
- #案例2:查询部门编号>=90的员工信息,按入职时间的先后顺序进行排序
- SELECT *
- FROM employees
- WHERE department_id>=90
- ORDER BY hiredate ASC;
- #案例3:按年薪的高低显示员工的信息和年薪[按表达式排序]
- SELECT *,salary*12*(1+IFNULL(commission_prt,0)) 年薪
- FROM employees
- ORDER BY salary*12*(1+IFNULL(commission_prt,0)) DESC; 或 ORDER BY 年薪 DESC;
- #案例5:按姓名的长度显示员工的姓名和工资[按函数排序]
- SELECT LENGTH(last_name) 字节长度,last_name,salary
- FROM employees
- ORDER BY LENGTH(last_name) DESC;
- #案例6:查询员工信息,要求先按工资升序,再按员工编号降序[按多个字段排序]
- SELECT *
- FROM employees
- ORDER BY salary ASC,employee_id DESC;
复制代码 - ceil():向上取整,返回 >= 该参数的最小整数
floor():向下取整,返回 20000,显示A级别 如果工资 > 15000,显示B级别 如果工资 > 10000,显示C级别 否则,显示D级别SELECT salary,CASEWHEN salary>20000 THEN 'A'WHEN salary>15000 THEN 'B'WHEN salary>10000 THEN 'C'ELSE 'D'END AS 工资级别FROM employees;[/code]
加密与解密函数
函数用法PASSWORD(str)返回字符串str的加密版本,41位长的字符串。加密结果不可逆,常用语用户的密码加密。在mysql8.0中被弃用。MD5(str)返回字符串str的md5加密后的值,也是一种加密方式。若参数为NULL,则会返回NULL。不可逆。SHA(str)从原明文密码str计算并返回加密后的密码字符串,当参数为 NULL 时,返回 NULL。不可逆。ENCODE(value,password_seed)返回使用 password_seed 作为加密密码加密value。mysql8.0后被弃用。DECODE(value,password_seed)返回使用password_seed作为加密密码解密valuemysql 信息函数
函数用法VERSION()返回当前MySQL的版本号CONNECTION_ID()返回当前MySQL服务器的连接idDATABASE(),SCHEMA()返回MySQL命令行当前所在的数据库USER(),CURRENT_USER()、SYSTEM_USER(), SESSION_USER()返回当前连接MySQL的用户名,返回结果格式为 “主机名@用户名”CHARSET(value)返回字符串value自变量的字符集COLLATION(value)返回字符串value的比较规则其他函数
函数用法FORMAT(value,n)返回对数字value进行格式化后的结果数据。n表示 四舍五入 后保留到小数点后n位CONV(value,from,to)将value的值进行不同进制之间的转换INET_ATON(ipvalue)将以点分隔的IP地址转化为一个数字INET_NTOA(value)将数字形式的IP地址转化为以点分隔的IP地址BENCHMARK(n,expr)将表达式expr重复执行n次。用于测试MySQL处理expr表达式所耗费的时间CONVERT(value USING char_code)将value所使用的字符编码修改为char_code分组函数
- 功能:用作统计使用,又称为聚合函数或统计函数或组函数。输入的是一组数据的集合,输出的是单个值。
- 分类:sum 求和、 avg 平均值、 max 最大值、 min 最小值、 count 计算个数;
- 特点:
- sum、avg一般用于处理数值型;max、min、count 可以处理任何类型;
- 以上分组函数都忽略 null 值;
- 可以和 distinct 搭配实现去重的运算;
- select 函数名(实参列表) [from 表]
- (1) 单行函数
- concat、length、ifnull等
- (2) 分组函数
- 做统计使用,又称为统计函数、聚合函数、组函数
复制代码
- count函数的详细介绍,一般使用 COUNT(*) 统计行数;
- SELECT LENGTH('张三丰hahaha');
- SHOW VARIVALE LIKE '%char%'; 查看字符集
复制代码
- 和分组函数一同查询的字段要求是 group by 后面的字段;
- SELECTV CONCAT(last_name,'_',first_name) 姓名 FROM employees;
复制代码 分组查询
- # 截取从指定索引处后面所有字符
- SELECT SUBSTR('李莫愁爱上了路站元',7) out_put;
- # 截取从指定所引处指定字符长度的字符
- SELECT SUBSTR('李莫愁爱上了路站元',1,3) out_put;
- #案例:姓名中首字符大写,其他字符小写,然后用 _ 拼接,显示出来
- SELECT CONTACT(UPPER(SUBSTR(last_name,1,1)),LOWER(SUBSTR(last_name),2)) out_put;
复制代码
- 明确:WHERE 一定放在 FROM 后面;
- 注意:查询列表必须特殊,要求是分组函数和 group by 后出现的字段;
- 当使用 ROLLUP 时,不能同时使用 ORDER BY 子句进行结果排序,即 ROLLUP 和 ORDER BY 是互相排斥的。
- SELECT TRIM('a' FROM 'aaaaa张aa翠山aaaaaa') AS out_put;
复制代码- SELECT LPAD('殷素素',10,'*') AS out_put; //10为总字符数
- SELECT LPAD('殷素素',2,'*') AS out_put; //殷素
复制代码
- group by 子句支持单个字段分组,多个字段分组(多个字段之间用逗号隔开,没有顺序要求),表达式或函数(用的较少);
- 也可以添加排序(排序放在整个分组查询的最后);
- 从 mysql8.0 开始,group by不再支持隐式排序。
- 当 group by 这列有 null 值时,group 会把他们当成是同一个直接聚合。
- 如果过滤条件中使用了聚合函数,则必须使用 HAVING 来替换 WHERE。否则,报错。
- 案例:
- SELECT RPAD('殷素素',12,'ab') AS out_put;
复制代码- SELECT ROUND(1.65);
- SELECT ROUND(1.567,2); // 1.57
复制代码 连接查询
- 含义:又称多表查询,当查询的字段来自多个表时;
- 笛卡尔乘积现象:表1有 m 行,表2有 n 行,结果 m*n 行
发生原因:没有有效的连接条件;
如何避免:添加有效的连接条件;
分类:
sql92标准:仅仅支持内连接
等值
非等值
自连接
也支持一部分外连接(用于 oracle、sqlserver,mysql 不支持)
sql99标准(推荐):支持内连接+外连接(左外和右外)+交叉连接
- 内连接
等值连接
非等值连接
自连接
- 外连接
左外连接
右外连接
全外连接(mysql不支持)
- 交叉连接
sql92 标准
等值连接
- 多表等值连接的结果为多表的交集部分;
- n表的连接,至少需要n-1个连接条件;
- 多表的顺序没有要求;
- 一般需要为表起别名;
- 可以搭配前面介绍的所有子句使用,比如排序、筛选、分组;
语法:- SELECT TRUNCATE(1.6999,1); //1.6
复制代码 案例:
- 为表起别名
- 提高语句的简洁度;
- 区分多个重名的字段;
- 注意:如果为表起了别名,则查询的字段就不能使用原来的表名去限定;
- SELECT YEAR(now());
- SELECT YEAR('1998-1-1') 年;
复制代码- STR_TO_DATE('9-13-1999','%m-%d-%Y') 1999-09-13
复制代码- DATE_FORMAT('2018/6/6','%Y年%m月%d日') 2018年06月06日
复制代码- SELECT VERSION();
- SELECT DATABASE();
- SELECT USER();
- SELECT password('字符'):返回该字符的密码形式 自动加密
- MD5('字符'):返回该字符的md5加密形式
复制代码 非等值连接
- if(条件表达式,表达式1,表达式2):如果条件表达式成立,返回表达式1;否则返回表达式2
复制代码- SELECT last_name,commission_pct,IF(commission_pct IS NULL,'没奖金,呵呵','有奖金,嘻嘻') 备注
- FROM employees;
复制代码 自连接
- case 要判断的字段或表达式
- when 常量1 then 要显示的值1或语句1;
- when 常量2 then 要显示的值2或语句2;
- ...
- else 要显示的值n或语句n;
- end
复制代码 sql99 语法
- #案例:要查询员工的工资,要求
- 部门号=30,显示的工资为1.3倍
- 部门号=40,显示的工资为1.4倍
- 部门号=50,显示的工资为1.5 倍
- 其他部门,显示的工资为原工资
- SELECT salary 原始工资,department_id,
- CASE department_id
- WHEN 30 THEN salary*1.3
- WHEN 40 THEN salary*1.4
- WHEN 50 THEN salary*1.5
- ELSE salary
- END AS 新工资
- FROM employees;
复制代码 内连接:inner
- case
- when 条件1 then 要显示的值1或语句1
- when 条件2 then 要显示的值2或语句2
- ...
- else 要显示的值n或语句n
- end
复制代码 分类:等值、非等值、自连接
- 等值连接
特点:
- 添加排序、分组、筛选;
- inner 可以省略;
- 筛选条件放在 where 后面,连接条件放在 on 后面,提高分离性,便于阅读;
- inner join 连接和 sql92 语法中的等值连接效果是一样的,都是查询多表;
- #案例:查询员工的工资的情况 如果工资 > 20000,显示A级别
- 如果工资 > 15000,显示B级别
- 如果工资 > 10000,显示C级别
- 否则,显示D级别
- SELECT salary,
- CASE
- WHEN salary>20000 THEN 'A'
- WHEN salary>15000 THEN 'B'
- WHEN salary>10000 THEN 'C'
- ELSE 'D'
- END AS 工资级别
- FROM employees;
复制代码 - 非等值连接
- ```sql
- SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;
- ```
复制代码 - 自连接
- ```sql
- SELECT COUNT(salary) FROM employees;
- SELECT COUNT(*) FROM employees; //只要某一行有一个不为null,就相当于+1(不包含NULL值)
- SELECT COUNT(1) FROM employees; //统计1的个数,相当于计算行数
- 效率:
- 如果使用的是 MyISAM 存储引擎,则三者效率相同,都是O(1)
- 如果使用的是 InnoDB 存储引擎,则三者效率:COUNT(*) = COUNT(1) > COUNT(字段)
- ```
复制代码 外连接
- 左外: left [outer]
- 右外: right [outer]
- 全外: full [outer]
应用场景:用于查询一个表中有,另一个表中没有的记录;
特点:
如果从表中有和它匹配的,则显示匹配的值;
如果从表中没有和它匹配的,则显示 null;
外连接查询结果=内连接结果 + 主表中有而从表中没有的记录;
- 左外连接,left join 左边的是主表;
右外连接,right join 右边的是主表;
全外连接,两边都是主表。
- 左外和右外交换两个表的顺序,可以实现同样的效果;
- 全外连接=内连接的结果+表1中有但表2没有的+表2中有的但表1没有的;
- ```
- SELECT AVG(salary),employee_id FROM employees; 有问题,AVG(salary)只有一行,employee_id有很多行
- ```
复制代码 交叉连接:cross
- #执行顺序
- SELECT column,group_function(column) 5
- FROM table 1
- [WHERE condition] 2
- GROUP BY group_by_expression 3
- [HAVING 分组后的筛选] 4
- [ORDER BY column]; 6
复制代码 sql99 语法新特性
自然连接
NATURAL JOIN 用来表示自然连接。我们可以把自然连接理解为 SQL92 中的等值连接。它会帮你自动查询两张连接表中所有相同的字段 ,然后进行等值连接 。- 为了更好的理解 grouy by 多个列和聚合函数的应用,我们可以假设在group by执行之后,生成了一个虚拟的中间表。相同的group by字段合并成一行,其余的字段分别写到一个单元格里。
- 对于id和number里面的单元格有多个数据的情况,使用聚合函数。聚合函数就是用来输入多个数据,输出一个数据的。
- #对name字段进行分组
- id name number
- 1 aa 2
- 2 3
- 3 4
- 4 bb 5
- 8 6
复制代码 USING 连接
当我们进行连接的时候,SQL99还支持使用 USING 指定数据表里的 同名字段 进行等值连接。但是只能配合JOIN一起使用。比如:- ```
- 数据源 位置 关键字
- 分组前筛选 原始表 group by子句的前面 where
- 分组后筛选 分组后的结果集 group by子句的后面 having
- ```
复制代码 子查询
含义:出现在其他语句中的 select 语句,称为子查询或内查询;
外部的查询语句,称为主查询或外查询。
外面的语句可以是 insert、update、delete、select 等,一般 select 作为外面语句较多。
分类:
- select 后面:
- from 后面:
- where 或 having 后面
- exists 后面(相关子查询)(返回的结果1或0,类似布尔操作)
- 标量子查询(单行子查询)(结果集是一个数据:一行一列)
- 列子查询(多行子查询)(结果集是一列:一列多行):一般搭配着多行操作符使用 in、any/some、 all
- 行子查询(结果集是一行:一行多列)
- 表子查询(结果集一般为多行多列)
where 或 haing 后面
特点:
<ul>子查询放在小括号内
子查询一般放在条件的右侧
标量子查询,一般搭配着单行操作符使用 > < >= (1)结果 SELECT * FROM employees WHERE salary>( SELECT salary FROM employees WHERE last_name = 'Abel' );#案例2:返回job_id与141号员工相同,salary比143号员工多的员工姓名,job_id和工资#(1)查询141号员工的job_id SELECT job_id FROM employees WHERE employee_id = 141#(2)查询143号员工的salary SELECT salary FROM employees WHERE employee_id = 143#(3)查询员工的姓名、job_id和工资,要求job_id=(1)并且salary>(2) SELECT last_name,job_id,salary FROM employees WHERE job_id = ( SELECT job_id FROM employees WHERE employee_id = 141 ) AND salary > ( SELECT salary FROM employees WHERE employee_id = 143 );#案例3:返回公司工资最少的员工的last_name,job_id和salary#(1)查询公司的最低工资 SELECT MIN(salary) FROM employees;#(2)查询last_name,job_id和salary,要求salary=(1) SELECT last_name,job_id,salary FROM employees WHERE salary = ( SELECT MIN(salary) FROM employees; );#案例4:查询最低工资大于50号部门最低工资的部门id和其最低工资#(1)查询50号部门的最低工资 SELECT MIN(salary) FROM employees WHERE department_id =50#(2)查询每个部门的最低工资 SELECT MIN(salary),department_id FROM employees GROUP BY department_id#(3)在(2)的基础上,满足min(salary)>(1) SELECT MIN(salary),department_id FROM employees GROUP BY department_id HAVING MIN(salary)>( SELECT MIN(salary) FROM employees WHERE department_id =50 );[/code]非法使用标量子查询:- #案例1:查询每个工种的最高工资
- SELECT MAX(salary),job_id
- FROM employees
- GROUP BY job_id;
- #案例2:查询每个位置上的部门个数
- SELECT COUNT(*),location_id
- FROM employees
- GROUP BY location_id;
- #案例3:查询邮箱中包含a字符的,每个部门的平均工资
- SELECT AVG(salary),department_id
- FROM employees
- WHERE email LIKE '%a%'
- GROUP BY department_id;
- #案例4:查询有奖金的每个领导手下员工的最高工资
- SELECT MAX(salary),manager_id
- FROM employees
- WHERE commission_pct IS NOT NULL
- GROUP BY manager_id;
- #案例5:查询哪个部门的员工个数>2
- (1) 查询每个部门员工个数
- SELECT COUNT(*),department_id
- FROM employees
- GROUP BY department_id;
- (2) 根据(1)的结果进行筛选,查询哪个部门的员工个数>2
- SELECT COUNT(*),department_id
- FROM employees
- GROUP BY department_id
- HAVING COUNT(*)>2;
复制代码 列子查询(多行子查询)
操作符含义IN / NOT IN等于列表中的任意一个ANY | SOME和子查询返回的某一个值比较ALL和子查询返回的所有值比较- #案例:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
- (1)查询每个工种有奖金的员工的最高工资
- SELECT MAX(salary),job_id
- FROM employees
- WHERE commission_pct IS NOT NULL
- GROUP BY job_id;
- (2)根据(1)结果继续筛选,最高工资>12000
- SELECT MAX(salary),job_id
- FROM employees
- WHERE commission_pct IS NOT NULL
- GROUP BY job_id
- HAVING MAX(salary)>12000;
- #案例:查询领导编号>102的每个领导手下的最低工资>5000的领导编号是哪个,以及其最低工资;
- (1)查询每个领导手下的员工最低工资
- SELECT MIN(salary),manager_id
- FROM employees
- GROUP BY manager_id;
- (2)添加筛选条件:编号>102
- SELECT MIN(salary),manager_id
- FROM employees
- WHERE manager_id > 102
- GROUP BY manager_id;
- (3)添加筛选条件:最低工资>5000
- SELECT MIN(salary),manager_id
- FROM employees
- WHERE manager_id > 102
- GROUP BY manager_id
- HAVING MIN(salary)>5000;
- > 按表达式或函数分组
- > 案例:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的的有哪些
- (1)查询每个长度的员工个数
- SELECT COUNT(*),LENGTH(last_name)
- FROM employees
- GROUP BY LENGTH(last_name);
- (2)添加筛选条件
- SELECT COUNT(*),LENGTH(last_name)
- FROM employees
- GROUP BY LENGTH(last_name)
- HAVING COUNT(*)>5;
- > 按多个字段分组
- #案例:查询每个部门每个工种的员工的平均工资
- SELECT AVG(salary),department_id,job_id
- FROM employees
- GROUP BY job_id,department_id;
- #添加排序
- #案例:查询每个部门每个工种的员工的平均工资,并且按平均工资的高低显示
- SELECT AVG(salary),department_id,job_id
- FROM employees
- WHERE department_id IS NOT NULL
- GROUP BY job_id,department_id
- ORDER BY AVG(salary) DESC;
复制代码 exists后面(相关子查询)
- SELECT 查询列表
- FROM 表1 别名, 表2 别名
- WHERE 表1.key = 表2.key
- [AND 筛选条件]
- [GROUP BY 分组字段]
- [HAVING 分组后的筛选]
- [ORDER BY 排序字段]
复制代码- #案列1:查询女生名和对应的男生名
- SELECT NAME,boyName
- FROM boys,beauty
- WHERE beauty.boyfriend_id = boys.id;
- #案例2:查询员工名和对应的部门名
- SELECT last_name,department_name
- FROM employees,departments
- WHERE employees.`department_id` = departments.`department_id`;
复制代码 子查询经典案例
- #案例:查询员工名、工种号、工种名
- SELECT e.last_name,e.job_id,j.job_title #employees.last_name错误
- FROM employees AS e,jobs j
- WHERE e.`job_id` = j.`job_id`;
复制代码 分页查询
应用查询:当要显示的数据,一页显示不全,需要分页提交 sql 请求。
语法:- #案例:查询有奖金的员工名、部门名
- SELECT last_name,department_name
- FROM employees e,departements d
- WHERE e.`department_id` = d.`department_id`
- AND e.`commission_pct` IS NOT NULL;
- #案例2:查询城市名中第二个字符为o的部门名和城市名
- SELECT dapartment_name,city
- FROM departments d,location l
- WHERE d.`location_id` = l.`location_id`
- AND city LIKE `_o%`;
复制代码 特点:
- #案例1:查询每个城市的部门个数
- SELECT COUNT(*) 个数,city
- FROM departments d,locations l
- WHERE d.`location_id` = l.`location_id`
- GROUP BY city;
- #案例2:查询有奖金的部门的部门名和部门的领导编号和该部门的最低工资
- SELECT department_name,d.`manager_id`,MIN(salary)
- FROM dapartment d,employees e
- WHERE d.`department_id` = e.`department_id`
- AND commission_pct IS NOT NULL
- GROUP BY department_name,d.mamager_id;
复制代码- #案例:查询每个工种的工种名和员工的个数,并且按员工的个数降序
- SELECT job_title,COUNT(*)
- FROM employees e,jobs j
- WHERE e.`job_id` = j.`job_id`
- GROUP BY job_title
- ORDER BY COUNT(*) DESC;
复制代码 union 联合查询
union:将多条查询语句的结果合并成一个结果
语法:- #案列:查询员工名、部门名和所在的城市
- SELECT last_name,department_name,city
- FROM employees e,department d,location l
- WHERE e.`department_id` = d.`department_id`
- AND d.`location_id` = l.`location_id`
- AND city LIKE 's%'
- ORDER BY department_name DESC;
复制代码 应用场景:要查询的结果来自于多个表,且多个表没有直接的连接关系,但查询的信息一致时。
特点:
- 要求多条查询语句的查询列数是一致的;
- 要求多条查询语句的查询的每一列的类型和顺序最好一致;
- union 关键字默认去重,如果使用 union all 可以包含重复项;
SELECT 的执行过程
查询的结构
- SELECT 查询列表
- FROM 表1 别名, 表2 别名
- WHERE 非等值的连接条件
- [AND 筛选条件]
- [GROUP BY 分组字段]
- [HAVING 分组后的筛选]
- [ORDER BY 排序字段]
复制代码 SELECT 执行顺序
- #案例1:查询员工的工资和工资级别
- SELECT salary,grade_level
- FROM employess e,job_grades g
- WHERE salary BETWEEN g.`lowest_sal` AND g.`hightest_sal`
- //AND g.`grade_level` = 'A';
复制代码 在 SELECT 语句执行这些步骤的时候,每个步骤都会产生一个 虚拟表,然后将这个虚拟表传入下一个步骤中作为输入。
SQL 的执行原理
- 首先先通过 CROSS JOIN 求笛卡尔积,相当于得到虚拟表 vt(virtual table) 1-1;
- 通过 ON 进行筛选,在虚拟表 vt1-1 的基础上进行筛选,得到虚拟表 vt1-2;
- 添加外部行。如果我们使用的是左连接、右连接或者全连接,就会涉及到外部行。也就是在虚拟表 vt1-2 的基础上增加外部行,得到虚拟表 vt1-3。
- 当我们拿到了查询数据表的原始数据,也就是最终的虚拟表 vt1。就可以在此基础上再进行 WHERE 阶段。在这个阶段中,会根据 vt1 表的结果进行筛选过滤,得到虚拟表 vt2.
- ......
六、DML语言的学习
插入语句
方式一:经典的插入
语法:- #案例:查询员工名和上级的名称
- SELECT e.employee_id,e.last_name,m.employee_id,m.last_name
- FROM employees e,employees m
- WHERE e.manager_id = m.employee_id;
复制代码 特点:
- 插入的值的类型要与列的类型一致或兼容;
- 不可以为 null 的列必须插入值,可以为 Null 的列如何插入值:
- 方式一:对应的 value 填 null;
- 方式二:字段和值都省略;
- 字段的个数和顺序不一定与原始表中的字段个数和顺序一致,但必须保证值和字段一一对应;
- 列数和值的个数必须一致;
- 可以省略列名,默认所有列,而且列的顺序和表中列的顺序一致;
方式二:
- SELECT 查询列表
- FROM 表1 别名 [连接类型]
- JOIN 表2 别名
- ON 连接条件
- [WHERE 筛选条件]
- [GROUP BY 分组]
- [HAVING 筛选条件]
- [ORDER BY 排序列表]
复制代码 两种方式大pk
- SELECT 查询列表
- FROM 表1 别名
- INNER JOIN 表2 别名
- ON 连接条件;
复制代码- #案例1:查询员工名、部门名
- SELECT last_name,department_name
- FROM employees e
- INNER JOIN departments d
- ON e.`department_id` = d.`department_id`;
- #案例2:查询员工名字中包含e的员工名和工种名(添加筛选)
- SELECT last_name,job_title
- FROM employees e
- INNER JOIN jobs j
- ON e.`job_id` = j.`job_id`
- WHERE e.`last_name` LIKE '%e%';
- #案例3:查询部门个数>3的城市名称和部门个数(添加分组+筛选)
- #(1)查询每个城市部门的个数
- #(2)在(1)结果上筛选满足条件的
- SELECT city,COUNT(*) 部门个数
- FROM departments d
- INNER JOIN locations l
- ON d.`location_id` = l.`location_id`
- GROUP BY city
- HAING COUNT(*)>3;
- #案例4:查询哪个部门的员工个数>3的部门名和员工个数,并按个数降序(添加排序)
- #(1)查询每个部门的员工个数
- SELECT COUNT(*),department_name
- FROM employees e
- INNER JOIN departments d
- ON e.`department_id` = d.`department_id`
- GROUP BY department_name;
- #(2)在(1)结果上筛选员工个数>3的记录,并排序
- SELECT COUNT(*),department_name
- FROM employees e
- INNER JOIN departments d
- ON e.`department_id` = d.`department_id`
- GROUP BY department_name
- HAVING COUNT(*)>3
- ORDER BY COUNT(*) DESC;
- #案例5:查询员工名、部门名、工种名,并按部门名排序
- SELECT last_name,department_name,job_title
- FROM employees e
- INNER JOIN departments d ON e.`department_id` = d.`department_id`
- INNER JOIN jobs j ON e.`job_id`=j.`job_id`
- ODER BY department_name DESC;
复制代码 修改语句
修改单表的记录
语法:- #案例1:查询员工的工资级别
- SELECT salary,grade_level
- FROM employees e
- JOIN job_grade e
- ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`;
- #案例2:查询工资级别的个数>20的个数,并且按工资级别降序
- SELECT COUNT(*),grade_level
- FROM employees e
- JOIN job_grade e
- ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`
- GROUP BY grade_level
- HAVING COUNT(*)>20
- ORDER BY grade_level DESC;
复制代码 修改多表的记录(补充)
- sql92 语法:
- #案例:查询姓名中包含字符k的员工的名字、上级的名字
- SELECT e.last_name,m.last_name
- FROM employees e
- JOIN employees m
- ON e.`manager_id` = m.`manager_id`
- WHERE e.`last_name` LIKE '%k%';
复制代码 - sql99 语法:
- #案例:查询男朋友 不在男明星表的女明星名
- SELECT b.name,bo.*
- FROM beauty b
- LEFT OUTERF JOIN boys bo
- ON b.`boyfriend_id` = bo.`id`
- WHERE bo.`id` IS NULL; //问题:为什么用boys.id为NULL就可以了呢,实际上的boys表里的id是主键,根本不可能为NULL啊?
- #案例1:查询哪个部门没有员工
- #左外
- SELECT d.*,e.employee_id
- FROM departments d
- LEFT OUTER JOIN employees e
- ON d.`department_id`=e.`department_id`
- WHERE e.`employee_id` IS NULL;
- #案例2:查询哪个城市没有部门
- SELECT city
- FROM department d
- RIGHT OUTER JOIN locations l
- ON d.location_id = l.location_id
- WHERE d.department_id IS NULL;
- #案例3:查询部门为SAL或IT的员工信息
- SELECT e.*,d.department_name
- FROM departments d
- LEFT OUTER JOIN employees e
- ON d.department_id = e.department_id
- WHERE d.department_name IN ('SAL','IT');
复制代码
- SELECT 查询列表
- FROM 表1 别名
- CROSS JOIN 表2 别名;
- #特点:类似于笛卡尔乘积
复制代码 删除语句
方式一:delete
单表的删除
- #sql92中:
- SELECT employee_id,last_name,department_name
- FROM employees e JOIN departments d
- ON e.`department_id` = d.`department_id`
- AND e.`manager_id` = d.`manager_id`;
- #在sql99中可写成:
- SELECT employee_id,last_name,department_name
- FROM employees e NATURAL JOIN departments d;
复制代码 多表的删除
- sql92 语法
- SELECT employee_id,last_name,department_name
- FROM employees e JOIN departments d
- USING (department_id);
复制代码 - sql99 语法
- #案例1:谁的工资比Abel高?
- #(1)查询Abel的工资
- SELECT salary
- FROM employees
- WHERE last_name = 'Abel'
- #(2)查询员工信息,满足 salary>(1)结果
- SELECT *
- FROM employees
- WHERE salary>(
- SELECT salary
- FROM employees
- WHERE last_name = 'Abel'
- );
- #案例2:返回job_id与141号员工相同,salary比143号员工多的员工姓名,job_id和工资
- #(1)查询141号员工的job_id
- SELECT job_id
- FROM employees
- WHERE employee_id = 141
- #(2)查询143号员工的salary
- SELECT salary
- FROM employees
- WHERE employee_id = 143
- #(3)查询员工的姓名、job_id和工资,要求job_id=(1)并且salary>(2)
- SELECT last_name,job_id,salary
- FROM employees
- WHERE job_id = (
- SELECT job_id
- FROM employees
- WHERE employee_id = 141
- ) AND salary > (
- SELECT salary
- FROM employees
- WHERE employee_id = 143
- );
- #案例3:返回公司工资最少的员工的last_name,job_id和salary
- #(1)查询公司的最低工资
- SELECT MIN(salary)
- FROM employees;
- #(2)查询last_name,job_id和salary,要求salary=(1)
- SELECT last_name,job_id,salary
- FROM employees
- WHERE salary = (
- SELECT MIN(salary)
- FROM employees;
- );
- #案例4:查询最低工资大于50号部门最低工资的部门id和其最低工资
- #(1)查询50号部门的最低工资
- SELECT MIN(salary)
- FROM employees
- WHERE department_id =50
- #(2)查询每个部门的最低工资
- SELECT MIN(salary),department_id
- FROM employees
- GROUP BY department_id
- #(3)在(2)的基础上,满足min(salary)>(1)
- SELECT MIN(salary),department_id
- FROM employees
- GROUP BY department_id
- HAVING MIN(salary)>(
- SELECT MIN(salary)
- FROM employees
- WHERE department_id =50
- );
复制代码
- SELECT MIN(salary),department_id
- FROM employees
- GROUP BY department_id
- HAVING MIN(salary)>(
- SELECT salary
- FROM employees
- WHERE department_id =50
- );
复制代码 方式二:truncate (清空)
- #案例1:返回 location_id 是 1400 或 1700 的部门中所有员工姓名
- #(1)查询location_id是1400或1700的部门编号
- SELECT DISTINCT department_id
- FROM departments
- where location_id IN(1400,1700)
- #(2)查询员工姓名,要求部门号是(1)列表中的某一个
- SELECT last_name
- FROM employees
- WHERE deapartment_id IN(
- SELECT DISTINCT department_id
- FROM departments
- where location_id IN(1400,1700)
- );
- #案例2:查询其它工种中比job_id为`IT_PROG`工种任一工资低的员工的员工号、姓名、job_id 和 salary
- #(1)查询job_id为`IT_PROG`部门任一工资
- SELECT DISTINCT salary
- FROM employees
- WHERE job_id='IT_PROG'
- #(2)查询员工号、姓名、job_id以及salary,salary<(1)的任意一个
- SELECT last_name,employee_id,job_id,salary
- FROM employees
- WHERE salary < ANY(
- SELECT DISTINCT salary
- FROM employees
- WHERE job_id='IT_PROG'
- )AND job_id<>'IT_PROG';
- 或
- SELECT last_name,employee_id,job_id,salary
- FROM employees
- WHERE salary < (
- SELECT MAX(salary)
- FROM employees
- WHERE job_id='IT_PROG'
- )AND job_id<>'IT_PROG';
复制代码 delete PK truncate (重点)
- delete 可以添加 where 条件,truncate 不能加;
- truncate 删除,效率高一丢丢;
- 假如要删除的表中有自增长列,如果用 delete 删除后,再插入数据,自增长列的值从断点开始,而 truncate 删除后,再插入数据,自增长列的值从1开始;
- truncate 删除没有返回值,delete 删除有返回值;
- truncate 删除不能回滚,delete 删除可以回滚;
MySQL8 新特性:计算列
什么叫计算列呢?简单来说就是某一列的值是通过别的列计算得来的。例如,a列值为1、b列值为2,c列不需要手动插入,定义a+b的结果为c的值,那么c就是计算列,是通过别的列计算得来的。- #案例:查询员工编号最小且工资最高的员工信息
- #(1)查询最小的员工编号
- SELECT MIN(employee_id)
- FROM employees
- #(2)查询最高工资
- SELECT MAX(salary)
- FROM employees
- #(3)查询员工信息
- SELECT *
- FROM employees
- WHERE employee_id=(
- SELECT MIN(employee_id)
- FROM employees
- )AND salary=(
- SELECT MAX(salary)
- FROM employees
- );
- SELECT *
- FROM employees
- WHERE (employee_id,salary)=(
- SELECT MIN(employee_id),MAX(salary)
- FROM employees
- );
复制代码 七、DDL语言的学习
标识符命名规则
- 数据库名、表名不得超过30个字符,变量名限制为29个。
- 必须只能包含 A-Z,a-z,0-9,_ 共63个字符。
- 数据库名、表名、字段名等对象中间不要包含空格。
- 同一个 MySQL 软件中,数据库不能同名;同一个库中,表不能重名;同一个表中,字段不能重名。
- 必须保证你的字段没有和保留字、数据库系统或常用方法冲突。如果坚持使用,请在 SQL 语句中使用着重号引起来。
- 保持字段名和类型的一致性:在命名字段并为其指定数据类型的时候一定要保证一致性,假如数据类型在一个表里是整数,那在另一个表里可别变成字符型了。
库的管理
- #案例1:查询每个部门的员工个数
- SELECT d.*,(
- SELECT COUNT(*)
- FROM employees
- WHERE e.department_id = d.`department_id`
- ) 个数
- FROM departments d;
- #案例2:查询员工号=102的部门名
- SELECT (
- SELECT department_name
- FROM departments d
- INNER JOIN employees e
- ON d.department_id = e.department_id
- WHERE e.employee_id = 102
- ) 部门名;
复制代码 1. 库的创建
- #案例1:查询每个部门的平均工资的工资等级
- #(1)查询每个部门的平均工资
- SELECT AVG(salary),department_id
- FROM employees
- GROUP BY department_id
- #(2)连接(1)的结果集和job_grade表,筛选条件平均工资between lowest_sal and highest_sal
- SELECT ag_dep.*,g.`grade_level`
- FROM(
- SELECT AVG(salary) ag,department_id
- FROM employees
- GROUP BY department_id
- ) ag_dep
- INNER JOIN job_grade g
- ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;
- #案例2:查询各部门中工资比本部门平均工资高的员工的员工号,姓名和工资
- #(1)查询各部门的平均工资
- SELECT AVG(salary),department_id
- FROM employees
- GROUP BY department_id;
- #(2)连接(1)结果集和 employees 表,进行筛选
- SELECT employee_id,last_name,salary,e.department_id
- FROM employees e
- INNER JOIN (
- SELECT AVG(salary) ag,department_id
- FROM employees
- GROUP BY department_id;
- )ag_dep
- ON e.department_id = ag_dep.department_id
- WHERE salary > ag_dep.ag;
复制代码 2. 库的修改
- 语法:
- exists(完整的查询语句) 问题:exists(NULL)?
- 结果:
- 1或0
复制代码 3. 库的删除
- #案例1:查询有员工的部门名
- SELECT department_name
- FROM departments d
- WHERE EXISTS(
- SELECT *
- FROM employees e
- WHERE e.`department_id`= d.`department_id`
- );
- #in
- SELECT department_name
- FROM departments d
- WHERE d.`deparment_id` IN (
- SELECT department_id
- FROM employees
- );
- #案例2:查询没有女朋友的男生信息
- #in
- SELECT bo.*
- FROM boys bo
- WHERE bo.id NOT IN(
- SELECT boyfriend_id
- FROM beauty
- );
- #exists
- SELECT bo.*
- FROM boys bo
- WHERE NOT EXISTS(
- SELECT boyfriend_id
- FROM beauty b
- WHERE bo.id = b.boyfriend_id
- );
复制代码 表的管理
- #案例1:查询每个部门的员工个数
- SELECT d.*,(
- SELECT COUNT(*)
- FROM employees
- WHERE e.department_id = d.`department_id`
- ) 个数
- FROM departments d;
- #案例2:查询员工号=102的部门名
- SELECT (
- SELECT department_name
- FROM departments d
- INNER JOIN employees e
- ON d.department_id = e.department_id
- WHERE e.employee_id = 102
- ) 部门名;
复制代码 1. 表的创建
- SELECT 查询列表 7
- FROM 表 1
- [JOIN type join 表2 2
- ON 连接条件 3
- WHERE 筛选条件 4
- GROUP BY 分组字段 5
- HAVING 分组后的筛选 6
- ORDER BY 排序的字段] 8
- LIMIT offset,size; 9
- # offset 要显示条目的起始索引(起始索引从0开始)
- # size 要显示的条目个数
- 根据执行顺讯,可以得出:
- 1. order by 后面的列必须是在 select 后面存在的;
- 2. select、having 或 order by 后面存在的非聚合列必须全部在 group by 中存在。
复制代码 2. 表的修改
- #要显示的页数page 每页的条目数size
- SELECT 查询列表
- FROM 表
- LIMIET (page-1)*size,size;
复制代码 3. 表的删除
- #案例1:查询前五条员工信息
- SELECT * FROM employees LIMIT 0,5;
- 或
- SELECT * FROM employees LIMIT 5;
- #案例2:查询第11条——第25条
- SELECT * FROM employees LIMIT 10,15;
复制代码 4. 表的复制
- 查询语句1
- union [all]
- 查询语句2
- union [all]
- ......
- #案例:查询部门编号>90或邮箱包含a的员工信息
- SELECT * FROM employees WHERE email LIKE '%a%'
- UNION
- SELECT * FROM employees WHERE department_id >90;
复制代码 常见数据类型介绍
- 数值型:
- 字符型:
- 较短的文本:char、varchar
- 较长的文本:text、blob(较长的二进制数据)
- 日期型
类型类型举例整数类型TINYINT、SMALLINT、MEDIUMINT、INT(或INTEGER)、BIGINT浮点类型FLOAT、DOUBLE定点数类型DECIMAL位类型BIT日期时间类型YEAR、TIME、DATE、DATETIME、TIMESTAMP文本字符串类型CHAR、VARCHAR、TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT枚举类型ENUM集合类型SET二进制字符串类型BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBLOB、LONGBLOBJSON类型JSON对象、JSON数组空间数据类型单值:GEOMETRY、POINT、LINESTRING、POLYGON;集合:MULTIPOINT、MULTILINESTRING、MULTIPOLYGON、 GEOMETRYCOLLECTION其中,常用的几类类型介绍如下:
[table][tr]数据类型描述[/tr][tr][td]INT[/td][td]从-231到231-1的整型数据。存储大小为 4个字节[/td][/tr][tr][td]CHAR(size)[/td][td]定长字符数据。若未指定,默认为1个字符,最大长度255[/td][/tr][tr][td]VARCHAR(size)[/td][td]可变长字符数据,根据字符串实际长度保存,必须指定长度[/td][/tr][tr][td]FLOAT(M,D)[/td][td]单精度,占用4个字节,M=整数位+小数位,D=小数位。 D |