一:相关概念
- DB:数据库(database):存储数据的仓库,保存一系列有组织的数据。
- DBMS:数据库管理系统(database management system):数据库是通过DBMS创建和操作的容器(又称数据库软件)。常见有:MySQL、Oracle、DB2、SqlServer等。
- SQL:结构化查询语言(structure query language):专门用来与数据库通信的语言。
二:初始MySQL
(一)、启动MySQL服务
启动:
方式1:计算机右击 ——>管理——>服务和应用程序——>服务——>MySQL——>启动
方式2:用管理员身份去打开cmd窗口——>net start mysqld
登录:
方式1:打开client客户端——>输入密码(不建议,因为只能登录root用户)
方式2:用管理员身份去打开cmd窗口——>mysql -h localhost -P 3306 -u root -p——>输入密码
(二)、MySQL常见命令
1、查看但前所有数据库
show databases;
2、查看但前数据库所有表
show TABLES;
SELECT DATABASE();
3、创建表
create table 表名(
列名 列类型,
列名 列类型
);
4、查询表结构
desc stu1;
5、查看服务器版本
select version();
(三)、MySQL语法规范
1、不区分大小写,但建议关键字大写,表名、列名消息;
2、每条命令用分号结尾;
3、每条命令根据需要,可以缩进或换行;
4、 注释;
单行注释:#注释文字
单行注释:-- 注释文字
多行注释:/* 注释文字 */
三、DQL语言
数据查询语言(Data Query Language):
# 1、基础查询
/*
语法:
select 查询列表 FROM 表名;
特点:
查询列表可以是:表中的字段、常量值、表达式、函数
查询的结果是一个虚拟的表格
*/
USE myemployees;
/*
需要进入数据库
*/
# 1.1、查询表中的单个字段
SELECT last_name from employees;
# 1.2、查询表中多个字段
SELECT last_name,salary,email from employees;
# 1.3、查询表中的所有字段
SELECT * FROM employees;
# 1.4、查询常量值
SELECT 100;
SELECT '张三';
# 1.5、查询表达式
SELECT 100%98;
# 1.6、查询函数
SELECT VERSION();
# 1.7、起别名
/*
便于理解
如果要查询的字段有重名情况,使用别名可以区分开来
*/
# ①、方式一:使用AS
SELECT 100%98 AS 结果;
SELECT last_name AS 姓,first_name AS 名 FROM employees;
# ②、方式二:使用空格
SELECT last_name 姓,first_name 名 FROM employees;
# 案例:查询salary,显示结果为out put【需要将结果名加双引号、单引号、着重号等】
SELECT salary AS "out put" FROM employees;
SELECT salary AS 'out put' FROM employees;
SELECT salary AS `out put` FROM employees;
# 1.8、去重
# 案例:查询员工表中涉及到的所有部门编号
SELECT DISTINCT department_id FROM employees;
# 1.9、+号的作用
/*
java中+号的作用
运算符:两个操作符都为数值型
连接符:只要有一个操作数为字符串
mysql中+号的作用
仅仅只有一个运算符的功能
SELECT 100+90; 两个操作数都为数值型,则做加法运算
SELECT '123'+90; 其中有一个操作数为字符型,试图将字符型转换为数值型,如果转换成功,再做加法运算
SELECT '张三'+90; 如果转换失败,则将字符型数值转换为0,再做加法运算
SELECT null+90; 只要其中一方为null,则结果一定为null
mysql中concat()函数的作用
SELECT CONCAT(last_name,16);如果参数是字符类型,则进行拼接;如果是数值类型将其转换为字符类型进行拼接
*/
# 案例:只拼接字符串
SELECT CONCAT('a','b','c') AS abc;
# 案例:查询员工名和姓连接成一个字段,并显示为 姓名
SELECT CONCAT(last_name,first_name) AS 姓名 FROM employees;
============================================================================================================================================================================
# 2、条件查询
/*
语法:
select 查询列表 FROM 表名 WHERE 筛选条件;
③ ① ② (执行顺序)
分类:
按条件表达式筛选
条件运算符:[>] [<] [=] [!=] [<>] [>=] [<=]
按逻辑表达式筛选【作用:用于连接条件表达式】
逻辑运算符:[&&] [||] [!] [and] [or] [not]
&&和and:两个条件都为true,结果为true,反之为false
||或or:只要有一个条件为true,结果为true,反之为false
!或not:如果连接的条件本身为false,结果为true,反之为false
模糊查询
[like] [between] [in] [is null]
*/
# 2.1、按条件表达式筛选
# 案例1:查询员工工资大于12000的员工信息
SELECT * from employees WHERE salary>12000;
# 案例2:查询部门编号不等于90号的员工名和部门编号
SELECT last_name,department_id from employees WHERE department_id <> 90;
# 2.2、按逻辑表达式筛选
# 案例1:查询工资在10000到20000之间的员工名、工资以及奖金
SELECT last_name,salary,commission_pct FROM employees WHERE salary>=10000 AND salary<=20000;
# 案例2:查询部门编号不是在60-90之间,或者工资高于15000的员工信息
SELECT * FROM employees WHERE NOT(department_id>=60 AND department_id <=90) OR salary>15000;
# 2.3、模糊查询
/*
[like] 特点:一般和通配符搭配使用【% 任意多个字符,包含0个字符、_ 任意单个字符】
[between and] 特点:可以提高语句的简洁度、包含临界值、两个临界值不能调换顺序
[in] 特点:使用in提高语句简单度、in列表的值类型必须统一或兼容、不支持通配符('%a%')【判断某字段的值是否属于in列表中的某一项】
[is null] 因为=或<>不能判断null值,而is null 和 is not null 以及 <=>(安全等于)可以判断null值,同时 <=> 也可以判断普通值
[is not null]
[<=>]
*/
--------- LIKE -------------
# 案例1:查询员工名中包含字符a的员工信息
SELECT * FROM employees WHERE last_name LIKE '%a%';
# 案例2:查询员工名中第三个字符为c,第五个字符为h的员工名和工资
SELECT last_name,salary FROM employees WHERE last_name LIKE '__c_h%';
# 案例3:查询员工名中第二个字符为_的员工名
SELECT last_name FROM employees WHERE last_name LIKE '_\_%';
SELECT last_name FROM employees WHERE last_name LIKE '_$_%' ESCAPE '$';
-------- BETWEEN AND -------------
# 案例4:查询员工编号在100到120之间的员工信息
SELECT * FROM employees WHERE employee_id BETWEEN 100 AND 120;
SELECT * FROM employees WHERE employee_id >=100 AND employee_id <=120;
------------ IN -------------------
# 案例5:查询员工的工种编号是 IT_PROG、AD_VP、AD_PRES中的一个员工名和工种编号
SELECT last_name,job_id FROM employees WHERE job_id IN ('IT_PROG','AD_VP','AD_PRES');
---------- is null -------------------
# 案例6:查询没有奖金的员工名和奖金率
SELECT last_name,commission_pct FROM employees WHERE commission_pct is null;
SELECT last_name,commission_pct FROM employees WHERE commission_pct <=> null;
# 案例7:查询有奖金的员工名和奖金率
SELECT last_name,commission_pct FROM employees WHERE commission_pct is NOT NULL;
------------ <=> -----------------
# 案例8:查询员工工资为12000的员工信息
SELECT * FROM employees WHERE salary <=> 12000;
============================================================================================================================================================================
# 3、排序查询
/*
语法:
SELECT 查询列表 FROM 表名 【可以加where筛选条件】 ORDER BY 排序列表 【ASC | DESC】
特点:
ASC代表升序、DESC代表降序、如果不写,默认为升序
ORDER BY子句中可以支持单个字段、多个字段、表达式、函数、别名
ORDER BY子句一般放在查询语句的最后面,但limit子句除外
*/
# 3.1、一般排序
# 案例:查询员工信息,要求工资从高到低排序
SELECT last_name ,salary FROM employees ORDER BY salary DESC;
# 3.2、添加筛选条件排序
# 案例:查询部门编号大于等于90,按入职时间进行排序
SELECT department_id,hiredate FROM employees WHERE department_id >= 90 ORDER BY hiredate;
# 3.3、按表达式排序
# 案例:按年薪的高低显示员工的信息和年薪
SELECT last_name,salary*12*(1+IFNULL(commission_pct,0)) AS 年薪 FROM employees ORDER BY salary*12*(1+IFNULL(commission_pct,0));
# 3.4、按别名排序
# 案例:按年薪的高低显示员工的信息和年薪
SELECT last_name,salary*12*(1+IFNULL(commission_pct,0)) AS 年薪 FROM employees ORDER BY 年薪;
# 3.5、按函数排序
# 案例:按姓名长度显示员工的姓名和工资
SELECT last_name,salary FROM employees ORDER BY LENGTH(last_name);
# 3.6、按多个字段排序
# 案例:查询员工信息,要求先按工资排序,再按员工编号排序
SELECT last_name,salary,employee_id FROM employees ORDER BY salary ASC,employee_id DESC;
============================================================================================================================================================================
# 4、常见函数
/*
功能:
类似于Java中的方法,将一组逻辑语句封装在方法体中,只对外暴露方法名
好处:
隐藏了实现细节、提高代码的重用性
调用:
SELECT 函数名(实参列表) 【FROM 表名 -如果用到表,则需要加上】;
特点:
函数名、函数功能、返回值
分类:
单行函数:concat、length、substr、instr、trim、upper、lower、lapd、rapd、replace、round、ceil、floor、truncate、mod、now、curdata、curtime、
year、month、monthname、str_to-date、date_format、version、database、user、if、case、ifnull、isnull等【做处理使用】
分组函数(统计函数、聚合函数、组函数): 【做统计使用】
*/
# 4.1、单行函数
/*
字符函数
数学函数
日期函数
其他函数
流程控制函数
*/
# 4.1.1、字符函数
-- ------------LENGTH(str)---[获取参数值得字节个数]-------
SELECT LENGTH('张三丰');
SELECT LENGTH('abc');
SHOW VARIABLES LIKE '%CHAR%'
-- ------------concat(str)---[拼接字符串]---------------
SELECT CONCAT(first_name,'---',last_name) AS 姓名 FROM employees;
-- ------------UPPER(str)、LOWER(str)---[改变字符串大小写]-------
SELECT UPPER('join');
# 案例1:将姓变大写,名变小写,然后再拼接
SELECT CONCAT(LOWER(first_name),'+',UPPER(last_name)) AS 姓名 FROM employees;
-- ------------SUBSTR(str)、SUBSTRING(str)---[截取字符]【索引从1开始、步长为字符长度】-------
SELECT SUBSTR('张三丰是一代宗师!',5) AS out_put;
SELECT SUBSTR('张三丰是一代宗师!',1,3) AS out_put;
SELECT SUBSTR('abcde',1,1);
# 案例2:姓名中首字符大写,其他字符小写然后用_拼接,显示出来
SELECT CONCAT(UPPER(SUBSTR(first_name,1,1)),LOWER(SUBSTR(first_name,2)),'_',LOWER(last_name)) AS 姓名 FROM employees;
-- ------------INSTR(str,substr)---[包含字符串]【返回第一次起始索引,如果找不到返回0】---------------
SELECT INSTR('我叫张三丰','张三丰');
-- ------------TRIM([remstr FROM] str)---[去前后空格、去前后不需要字符]---------------
SELECT LENGTH(TRIM(' 我还叫张三丰 ')) AS 名字的字节长度;
SELECT TRIM('a' FROM 'aaaaaaa张aaaa三丰aaaaaaaa') AS 真名;
-- ------------LPAD(str,len,padstr)---[用指定的字符实现左填充指定长度、如果超过则从右边截断]---------------
SELECT LPAD('张三丰',2,'*');
SELECT LPAD('张三丰',10,'*');
-- ------------RPAD(str,len,padstr)---[用指定的字符实现右填充指定长度、如果超过则从右边截断]---------------
SELECT RPAD('张三丰',2,'*');
SELECT RPAD('张三丰',10,'*');
-- ------------REPLACE(str,from_str,to_str)---[字符替换]---------------
SELECT REPLACE('武当掌门是成昆,一代宗师也是成昆!','成昆','张三丰') AS 到底是谁;
# 4.1.2、数学函数
-- ------------ROUND(X)---[四舍五入]---------------
SELECT ROUND(-3.4);
SELECT ROUND(1.5678,2);
-- ------------CEIL(X)-----[向上取整]【返回>=该参数的最小整数】---------------
SELECT CEIL(1.539);
SELECT CEIL(1.111);
SELECT CEIL(1.000);
SELECT CEIL(-1.02);
-- ------------FLOOR(X)---[向下取整]【返回<=该参数的最大整数】---------------
SELECT FLOOR(-9.99);
-- ------------TRUNCATE(X,D)---[截断]---------------
SELECT TRUNCATE(1.6984,2);
-- ------------MOD(N,M)---[取余,余数的符号和被除数相同]【MOD(a,b):a-a/b*b】---------------------
SELECT MOD(10,3);
SELECT 10%3;
SELECT MOD(-10,3);
SELECT MOD(10,-3);
SELECT MOD(-10,-3);
# 4.1.3、日期函数
-- ------------NOW()---[返回当前系统日期+时间]---------------------
SELECT NOW();
-- ------------CURDATE()---[返回当前系统日期]---------------------
SELECT CURDATE();
-- ------------CURTIME()---[返回当前系统时间]---------------------
SELECT CURTIME();
# 案例:获取指定的部分,年,月,日,时,分,秒
SELECT YEAR(NOW());
SELECT YEAR('1998-1-2');
SELECT YEAR(hiredate) FROM employees;
SELECT SUBSTR(CURTIME(),1,2);
SELECT MONTHNAME(NOW());
-- ------------STR_TO_DATE(str,format)---[将日期格式的字符转换成指定格式的日期]----------------
/*
格式:
[%Y:四位年份]、[%y:两位年份]、[%m:月份(01,02)]、[%c:月份(1,2)]、[%d:日(01,02)]、
[%H:小时(24制)]、[%h:小时(12制)]、[%i:分钟(01,02)]、[%s:秒(01,02)]
*/
SELECT STR_TO_DATE('2020-7-08','%Y-%c-%d');
# 案例:查询入职日期为1992-4-3的员工信息
SELECT hiredate,last_name FROM employees WHERE hiredate = '1992-4-3';
SELECT hiredate,last_name FROM employees WHERE hiredate = STR_TO_DATE('4-3 1992','%c-%d %Y');
-- ------------DATE_FORMAT(date,format)---[将日期转换为字符]---------------------
SELECT DATE_FORMAT(NOW(),'%Y年%m月%d日');
# 案例:查询有奖金的员工名和入职日期(xx月/xx日 xx年)
SELECT last_name,DATE_FORMAT(hiredate,'%m月/%d日 %Y年') FROM employees WHERE commission_pct IS NOT NULL;
-- ------------DATEDIFF(date,date)---[算出两个日期之间的天数]---------------------
# 案例:查询员工表中的最大入职时间和最小入职时间的相差天数 (DIFFRENCE)
SELECT DATEDIFF(MAX(hiredate),MIN(hiredate)) AS DIFFRENCE FROM employees;
# 4.1.4、其他函数
SELECT VERSION();
SELECT DATABASE();
SELECT USER();
# 4.1.5、流程控制函数
-- ----------IF(expr1,expr2,expr3)-------[ifelse的效果]----------------
SELECT IF(10>5,'大','小');
SELECT last_name,commission_pct,IF(commission_pct IS NULL,'没奖金','有奖金') FROM employees;
-- ----------case-------[switch case 的效果]----------------
/*
mysql中:
case 要判断的字段1或表达式
WHEN 常量1 THEN 要显示的值1或语句1;
WHEN 常量1 THEN 要显示的值2或语句2;
...
ELSE 要显示的值n或语句n;
END;
*/
# 案例:查询员工工资,要求:部门号=30,显示的工资为1.1倍、部门号=40,显示的工资为1.2倍、部门号=50,显示的工资为1.3倍、其他部门,显示原工资
SELECT department_id,salary AS 原工资,
CASE department_id
WHEN 30 THEN
salary*1.1
WHEN 40 THEN
salary*1.2
WHEN 50 THEN
salary*1.3
ELSE
salary
END AS 新工资 FROM employees;
-- ----------case-------[多重if 的效果]----------------
/*
java中:
if(){
语句1;
}else if(){
语句2;
}
...
else{
语句3;
}
mysql中:
CASE
WHEN 条件1 THEN 要显示的值1或语句1
WHEN 条件2 THEN 要显示的值2或语句2
...
ELSE 要显示的值n或语句n
END
*/
# 案例:查询员工的工资情况,如果工资>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 工资等级 FROM employees;
# 4.2、分组函数
/*
功能:
用作统计使用,又称聚合函数或统计函数或组函数
分类:
sum 求和、avg 平均值、max 最大值、min 最小值、count 计算个数
特点:
sum、avg一般用于处理数值型,max、min、count可以处理任何类型
以上分组函数函数都忽略null值
可以和distinct搭配实现去重的运算
一般使用COUNT(*)用作统计行数
和分组函数一同查询的字段要求是group by后的字段
*/
# 4.2.1、简单的使用
SELECT SUM(salary) FROM employees;
SELECT AVG(salary) FROM employees;
SELECT SUM(salary),COUNT(salary),AVG(salary) FROM employees;
# 4.2.2、忽略null值
SELECT SUM(commission_pct) FROM employees;
# 4.2.3、和distinct搭配
SELECT SUM(DISTINCT salary),SUM(salary) FROM employees;
SELECT COUNT(DISTINCT commission_pct),COUNT(commission_pct) FROM employees;
# 4.2.4、count函数详细介绍
/*
效率:
MYISAM存储引擎下,COUNT(*) 的效率高
INNODB存储引擎下,COUNT(*)和COUNT(*1) 的效率差不多,但是比COUNT(字段) 要高一些
*/
SELECT COUNT(salary) FROM employees;
SELECT COUNT(*) FROM employees;
SELECT COUNT(1) FROM employees;
SELECT COUNT('张三丰') FROM employees;
# 4.2.5、和分组函数一同查询的字段有限制
SELECT COUNT(salary),salary FROM employees GROUP BY salary;
============================================================================================================================================================================
# 5、分组查询
/*
语法:
SELECT 分组函数,列(要求必须出现在group by后面)FROM 表 【WHERE 筛选条件】 GROUP BY 分组列表 【ORDER BY 字句】;
注意:
查询列表必须特殊,要求是分组函数和group by后出现的字段
特点:
分组查询中的筛选条件分为两类
分组前筛选:数据源是原始表、位置放在group by子句的前面、关键字为where
分组后筛选:数据源是分组后的结果集、位置放在group by子句的后面、关键字为having
分组函数做条件一定是要放在having子句中
能用分组前筛选的,就优先考虑使用分组前筛选
GROUP BY子句支持单个字段分组,也支持多个分组,多个字段之间用逗号隔开,没有先后顺序
也可以添加排序(排序需要放在最后)
*/
# 5.1、简单的分组查询
# 案例1:查询每个工种的最高工资
SELECT MAX(salary),job_id AS 最高工资 FROM employees GROUP BY job_id;
# 案例2:查询每个位置的部门个数
SELECT COUNT(department_id),location_id FROM departments GROUP BY location_id;
# 5.2、添加分组前筛选条件的分组查询
# 案例1:查询邮箱中包含a字符的,每个部门的平均工资
SELECT AVG(salary),department_id FROM employees WHERE email LIKE '%a%' GROUP BY department_id;
# 案例2:查询有奖金的每个领导手下员工的最高工资
SELECT MAX(salary),manager_id FROM employees WHERE commission_pct IS NOT NULL GROUP BY manager_id;
# 5.3、添加分组后的筛选条件的分组查询
# 案例1:查询哪个部门的员工个数>2
SELECT COUNT(department_id) AS 个数,department_id FROM employees GROUP BY department_id HAVING COUNT(department_id)>2;
# 案例2:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
SELECT MAX(salary),job_id FROM employees WHERE commission_pct IS NOT NULL GROUP BY job_id HAVING MAX(salary)>12000;
# 案例3:查询领导编号>102的每个领导手下的最低工资>5000的领导编号是哪个,以及最低工资
SELECT MIN(salary),manager_id FROM employees WHERE manager_id >102 GROUP BY manager_id HAVING MIN(salary)>5000 ORDER BY MIN(salary);
# 案例4:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数>5的有哪些
SELECT COUNT(employee_id) FROM employees GROUP BY LENGTH(last_name) HAVING COUNT(employee_id)>5;
# 5.4、按多字段分组
# 案例:查询每个部门、每个工种的员工的平均工资
SELECT AVG(salary),department_id,job_id FROM employees GROUP BY department_id,job_id;
# 5.5、添加排序
# 案例1:查询每个部门、每个工种的员工的平均工资,并且按平均工资的高低显示,且部门不能为null
SELECT AVG(salary),department_id,job_id FROM employees WHERE department_id IS NOT NULL GROUP BY department_id,job_id ORDER BY AVG(salary);
# 案例2:查询每个部门、每个工种的员工的平均工资,并且按平均工资的高低显示,且只显示大于10000的
SELECT AVG(salary),department_id,job_id FROM employees GROUP BY department_id,job_id HAVING AVG(salary) ORDER BY AVG(salary);
============================================================================================================================================================================
# 6、连接查询
/*
含义:
又称多表查询,当查询的字段来自于多个表时,就会用到
笛卡尔乘积现象:【表1 有m行,表2有n 行,结果为m*n 行】
发生原因:没有有效的连接条件
如何避免:添加有效的连接条件
分类:
按年代分类:
sql92标准:仅仅支持内连接
sql99标准【推荐】:支持内连接+外连接(左外和右外)+交叉连接
按功能分类:
内连接:等值连接、非等值连接、自连接
外连接:左外连接、右外连接、全外连接
交叉连接
*/
# 错误案例:查询beauty表中name的boyname
/*
如果用下面的方法查的话,会出现笛卡尔积的错误情况
*/
SELECT name,boyName FROM boys,beauty;
# 改正:
SELECT name,boyName FROM beauty,boys WHERE beauty.boyfriend_id = boys.id;
# 6.1、sql92标准
# 6.1.1、等值连接
/*
多表等值连接的结果为多表的交集部分
N个表连接,至少需要N-1个连接条件
多表的顺序没有要求
一般需要为表起别名
可以搭配前面所学的所有子句使用,比如:排序、分组、筛选
*/
# 案例1、查询女神名对应的男神名
SELECT name,boyName FROM beauty,boys WHERE beauty.boyfriend_id = boys.id;
# 案例2:查询员工名和对应的部门名
SELECT last_name,department_name FROM employees,departments WHERE employees.department_id = departments.department_id;
# Ⅱ、为表起别名
/*
好处:
提高语句的简洁度
区分多个重名的字段
注意:
如果为表起了别名,则查询的字段就不能使用原来的表名去限定
*/
# 案例:查询员工名、工种号、工种名
SELECT last_name,e.job_id,job_title FROM employees AS e,jobs j WHERE e.job_id = j.job_id;
# Ⅲ、两个表的顺序是否可以调换
# 案例:查询员工名、工种号、工种名
SELECT last_name,e.job_id,job_title FROM jobs j , employees AS e WHERE e.job_id = j.job_id;
# Ⅳ、可以加筛选
# 案例1:查询没有奖金的员工名、部门名
SELECT last_name,department_name,commission_pct FROM employees e,departments d WHERE e.department_id=d.department_id AND commission_pct IS NOT NULL;
# 案例2:城市名中第二个字符为o的部门名和城市名
# Ⅴ、可以加分组
# 案例1:查询每个城市的部门个数
SELECT COUNT(department_id),l.city FROM departments d,locations l WHERE d.location_id = l.location_id GROUP BY l.city;
# 案例2:查询有奖金的每个部门的部门名和部门领导编号和该部门的最低工资
SELECT department_name,d.manager_id,MIN(salary) FROM departments d,employees e WHERE d.department_id=e.department_id
AND commission_pct IS NOT NULL GROUP BY department_name,d.manager_id;
# Ⅵ、可以加排序
# 案例:查询每个工种的工种名和员工的个数,并且按员工的个数降序
SELECT COUNT(j.job_id),j.job_title FROM jobs j,employees e WHERE j.job_id=e.job_id GROUP BY j.job_id ORDER BY COUNT(j.job_id) DESC;
# Ⅶ、实现三表连接
# 案例:查询员工名、部门名和所在城市
SELECT d.department_name,e.last_name,l.city FROM departments d,employees e,locations l WHERE e.department_id=d.department_id
AND d.location_id=l.location_id AND l.city LIKE '%s%';
# 6.1.2、非等值连接
# 案例:查询出员工的工资和工资级别
SELECT e.last_name,e.salary,s.grade FROM employees e,sal_grade s WHERE e.salary BETWEEN s.min_salary AND s.max_salary;
# 6.1.3、自连接
# 案例:查询工名和上级名称
SELECT e1.last_name AS employee_name,e2.last_name AS manager_name FROM employees e1,employees e2 WHERE e2.employee_id = e1.manager_id;
# 6.2、sql99标准
/*
语法:
select 查询列表
from 表1 表名 【连接类型】
join 表2 别名
on 连接条件
【where 筛选条件】
【group by】
内连:inner
外连:
左外:left[outer]
右外:right[outer]
全外:full[outer]
交叉连接:cross
*/
# 6.2.1、内连接
/*
语法:
select 查询列表
from 表1 别名
inner join 表2 别名
on 连接条件;
特点:
1.添加排序、分组、筛选
2.筛选条件放在where后面,连接条件放在on后面,提高分离性
3.inner join连接和sql92语法中的等值连接效果一样,都是查询多表交集
*/
# Ⅰ、等值连接
# 案例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 last_name LIKE '%e%';
# 案例3、查询部门个数>3的城市名和部门个数,(分组+筛选)
SELECT city,COUNT(department_id) A FROM locations l INNER JOIN departments d on l.location_id = d.department_id GROUP BY city HAVING COUNT(department_id)>3;
# 案例4、查询哪个部门的部门员工个数>3的部门名和员工个数,并按个数降序
SELECT department_name,COUNT(employee_id) FROM employees e INNER JOIN departments d on e.department_id = d.department_id GROUP BY d.department_id 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 j.job_id = e.job_id ORDER BY d.department_name DESC;
# Ⅱ、非等值连接
# 案例:查询部门编号在10-90之间的员工的工资级别,并按级别进行分组
SELECT department_id,employee_id,grade FROM employees e INNER JOIN sal_grade s on e.salary BETWEEN s.min_salary AND s.max_salary WHERE e.department_id BETWEEN 10 AND 90;
# Ⅲ、自连接
#案例:查询员工名和对应的领导名
SELECT e.last_name,e2.last_name as manage_name FROM employees e INNER JOIN employees e2 on e.manager_id=e2.employee_id;
# 6.2.2、外连接
/*
说明:
查询结果为主表中所有的记录,如果从表有匹配项,则显示匹配项;如果从表没有匹配项,则显示null
应用场景:
一般用于查询主表中有,但从表没有的记录
特点:
1、外连接分主从表,两表的顺序不能任意调换
2、左连接的话,left join左边为主表
3、右连接的话,right join右边为主表
4、左外和右外交换两个表的顺序,可以实现同样的效果
5、全外连接=内连接的结果+表1中有但表2中没有的+表2中有但表1中没有的
语法:
select 查询列表
from 表1 别名
left|right|full 【outer】 join 表2 别名
on 连接条件
where 筛选条件;
*/
# Ⅰ、左,右外连接
# 案例1:查询所有女神记录,以及对应的男神名,如果没有对应的男神,则显示为null
USE girls; USE myemployees;
SELECT g.name,b.boyName FROM beauty g LEFT JOIN boys b on g.boyfriend_id = b.id;
SELECT g.name,b.boyName FROM boys b RIGHT JOIN beauty g on g.boyfriend_id = b.id;
# 案例2:查询哪个部门没有员工,并显示其部门编号和部门名
SELECT d.department_id, d.department_name,e.last_name FROM departments d LEFT JOIN employees e on e.department_id = d.department_id WHERE e.last_name is null;
# Ⅱ、全外连接
SELECT b.*,bo.* FROM beauty b FULL OUTER JOIN boy bo on g.boyfriend_id = b.id;
# 6.2.3、交叉连接
SELECT b.*,bo.* FROM beauty b CROSS JOIN boys bo;
### sql92 和sql99
### 功能:sql99支持较多
### 可读性:sql99实现连接条件和筛选条件分离,可读性较高

### INNER JOIN:如果表中有至少一个匹配,则返回行
### LEFT JOIN:即使右表中没有匹配,也从左表返回所有的行
### RIGHT JOIN:即使左表中没有匹配,也从右表返回所有的行
### FULL JOIN:只要其中一个表中存在匹配,则返回行
============================================================================================================================================================================
============================================================================================================================================================================
============================================================================================================================================================================
四、DML语言
数据操作语言(Data Manipulation Language)
五、DDL语言
数据定义语言(Data Definition Language )
六、TCL语言
事务控制语言(Transaction Control Language)