MySql基础学习笔记

#进阶查询 1:基础查询
/*
语法
select 查询列表 from 表名
1.查询列表可以是:表中的字段、常量值、表达式、函数
2.查询的结果是一个虚拟的表格
*/
USE myemployees;
#1.查询表中的单个字段
SELECT 
  last_name 
FROM
  employees ;

#2.查询表中的多个字段
SELECT 
  last_name,
  salary,
  email 
FROM
  employees ;

#3.查询表中的所有字段
#方式1:
SELECT 
  `first_name`,`last_name`,`email`,`job_id`,`commission_pct`,`department_id` 
FROM
  employees ;
#方式2:
SELECT 
  * 
FROM
  employees ;

# 4 查询常量值
SELECT 100;
SELECT "john";

# 5查询表达式
SELECT 100*98;

# 6.查询函数
SELECT VERSION();
# 7.起别名
/*
1.便于理解
2.如果查询的字段有重名的情况,使用别名可以区分开来
*/
#方式1:使用 AS
SELECT 100%98 AS 结果;
SELECT last_name AS 姓,first_name AS 名 FROM employees;
#方式2:使用空格
SELECT last_name 姓,first_name 名 FROM employees;
#案例 查询salary,显示结果为 out put
SELECT salary AS "out put" FROM employees;
#8 去重
#案例:查询员工表中涉及到的所有的部门编号
SELECT  DISTINCT department_id FROM employees;

#9 +号的作用
/*
mysql中的加号+:仅仅只有一个功能:运算符
select 100+90; 两个操作数都为数值型,则做加法运算
select '123'+90; 其中一方为字符型,试图将字符型数值转化为数值型。如果转化成功,则继续做加法运算

select "john"+90; 如果转化失败,则将字符型的数值转化为0

select null+10; 只要其中一方为null,则结果肯定为null

*/
#查询员工名和姓连接成一个字段,并显示为 姓名
SELECT CONCAT('a','b','c') AS 结果;

SELECT CONCAT(last_name,first_name) AS  姓名 FROM employees;

#显示出表employees的全部列,各个列之间用逗号连接,列头显示为OUT_PUT

SELECT IFNULL(`commission_pct`,0) AS 奖金率,`commission_pct` FROM employees;


SELECT 
CONCAT(`first_name`,`last_name`,`job_id`,IFNULL(`commission_pct`,0)) AS out_put
FROM employees;

#进阶2:条件查询
/*
语法:
  select 
         查询列表
   from 
          表名 
   where    
          筛选条件;

分类:
     一、按条件表达式筛选  
     条件运算符:< > <> = != >= <=   
     二、按照逻辑表达式查询
     逻辑运算符: && || ! and or not
     作用:用于连接条件表达式 
     三、模糊查询
       like
       特点:一般与通配符搭配使用
       %:表示任意多个字符, 包含0个字符
       _:任意单个字符
       between and
       特点:使用between and 可以提高语句的简洁度
              包含有临界值
              两个临界值不要调换顺序    
       in
       含义:判断某字段的值是否属于in列表中的某一项
       特点:使用in提高语句的简洁度
             in 列表的值类型必须统一或兼容 
             
       is null
       注意:=或<>不能用于判断null值
             is null 或is not null 可以用来判断空值
                 
*/
# 一、按照条件表达式进行筛选

#案例1:查询员工工资>1200的员工
SELECT * FROM employees WHERE salary>12000;

#案例2:查询闭门编号不等于90号的员工名和部门编号
SELECT last_name, department_id FROM employees WHERE department_id <>90;
#二、按照逻辑表达式筛选
# 案例1:查询工资在10000与20000之间的员工名、工资以及奖金
SELECT last_name,salary,`commission_pct` FROM employees WHERE  salary>=10000 AND salary<=20000;
#案例2:查询部门编号不是在90与110之间,或者工资高于15000的员工信息
SELECT * FROM employees WHERE department_id <90 OR department_id >110 OR salary >15000;
#三、模糊查询

#1.like
#案例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 '_\_%';

SELECT last_name FROM employees WHERE last_name LIKE '_$_%' ESCAPE '$';

#2.between and
#案例1:查询员工编号在100到120之间的员工信息
SELECT * FROM employees WHERE employee_id BETWEEN 100  AND 120;

#3 in
# 案例:查询员工的工种编号是 IT_PROG、AD_VP、AD_PRES中的一个员工名和工种编号
SELECT last_name ,job_id FROM employees WHERE  job_id   IN('IT_PROT','AD_VP','AD_PRES');
 
#4 is null
#案例1:查询没有奖金的员工名和奖金率
SELECT last_name ,`commission_pct` FROM employees WHERE `commission_pct` IS  NOT NULL;

# 安全等于<=>
#案例1:查询没有奖金的员工名和奖金率
SELECT last_name ,`commission_pct` FROM employees WHERE `commission_pct` <=> NULL;
#案例2:查询工资为12000的员工信息
SELECT * FROM employees WHERE salary <=> 12000;
IS NULL:仅仅可以判断NULL值
<=>:既可以判断NULL值,又可以判断普通的数值
# 2 查询员工号为176的员工的姓名和部门号和年薪
SELECT last_name,department_id,salary*12*(1+IFNULL(commission_pct,0)) AS 年薪 FROM employees;

# 进阶3:排序查询

/*
引入
SELECT * FROM employees;

语法:
  slect 查询列表
  from 表
  【where 筛选条件】
  order by  排序列表 【asc|desc】
  
  特点:
    1.asc 代表的是升序,des代表的是降序 如果不写,默认的是升序
    2.order by 子句中可以支持单个字段、多个字段、表达式、函数、别名
    3.order by字句一般放在查询语句的最后面,但limit语句除外
*/

#案例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_pct,0)) 年薪 FROM employees ORDER BY salary*12*(1+IFNULL(commission_pct,0)) DESC;
#案例4:按年薪的高低显示员工的信息和年薪【按照别名排序】
SELECT *,salary*12*(1+IFNULL(commission_pct,0)) 年薪 FROM employees ORDER BY 年薪;
#案例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;
#1. 查询员工的姓名和部门号和年薪,按年薪降序按姓名升序 
SELECT 
  last_name,
 salary * 12 * (1+ IFNULL(commission_pct, 0)) 年薪 
  department_id 
FROM
  employees 
ORDER BY   年薪  ASC,
  last_name DESC ;

#2. 选择工资不在 8000 到 17000 的员工的姓名和工资,按工资降序 
SELECT last_name,salary
FROM employees
WHERE salary NOT BETWEEN 8000 AND 12000
ORDER BY  salary DESC;

#3. 查询邮箱中包含 e 的员工信息,并先按邮箱的字节数降序,再按部门号升序 
SELECT *
FROM employees
WHERE email LIKE '%e%' 
ORDER BY LENGTH (email) DESC, department_id ASC;


#进阶4:常见函数
/*
功能:类似于java的方法,将一组逻辑语句封装在方法体中,对外暴露方法名
好处:1.隐藏了实现细节 2.提高了代码的重用性
调用: select 函数名(实参列表) 【from 表】;
特点: 1 叫什么(函数名)
       2 干什么(函数功能)
分类:1.单行函数 
      如 concat、length、ifnull等
      2.分组函数    
      功能:统计使用,又称为统计函数、聚合函数、组函数  
      
 总结:
  字符函数:length concat substr instr trim upper lower lpad rpad  replace   
  数学函数: round ceil floor truncate mod
  日期函数: now curdate curtime year month day mothname  hour minute second str_to_date date_format
  其他函数:version database  user 
  控制函数: if case
*/

# 一、字符函数
#1.length 获取参数值的字节个数
SELECT LENGTH("john");
SELECT LENGTH("张三丰哈哈哈哈")
#2.concat 拼接字符串
SELECT CONCAT(last_name,"_",first_name) FROM employees;
#3 upper、lower
SELECT UPPER('john');
SELECT LOWER("joHN");
#示例:将姓变大写,名变小写,然后拼接、
SELECT CONCAT(UPPER(last_name),"_",LOWER(first_name)) 姓名 FROM employees;
# 4 substr substring 注意:索引是从1开始的
#截取从指定索引处后面所有字符
SELECT SUBSTR('李莫愁爱上了陆展元',7) out_put;
#截取从指定所索引处指定长度的字符长度
SELECT SUBSTR('李莫愁爱上了陆展元',1,3) out_put;
#案例:姓名中首字符大写,其他字符小写然后用_拼接,显示出来
SELECT CONCAT(UPPER(SUBSTR(last_name,1,1)),'_',LOWER(SUBSTR(last_name,2))) out_put FROM employees;
# 5 instr 返回子串第一次出现的索引,如果找不到返回0
SELECT INSTR("杨不悔爱上了殷六侠","殷六侠") AS out_put;
# 6 trim
SELECT LENGTH(TRIM("      张翠山      ")) AS out_put;

SELECT TRIM('a' FROM "aaaaaaaaaaa张翠山aaaaaaaaaaa") AS out_put;
#7 lpad 用指定1字符实现左填充指定的长度
SELECT LPAD("殷素素",10,"*") AS out_put;
#8 rpad 用指定1字符实现右填充指定的长度
SELECT RPAD("殷素素",12,"ab") AS out_put;
#9.replace 替换
SELECT REPLACE("张无忌爱上了周芷若","周芷若","赵敏") AS out_put;

#二、数学函数
#1.round 四舍五入
SELECT ROUND(1.44);
SELECT ROUND(1.347,2);
#ceil 向上取整,返回大于等于该参数的最小整数
SELECT CEIL(-1.52);
#floor 向下取整,返回小于等于该参数的最大整数
SELECT FLOOR(9.99);
#truncate 截取
SELECT TRUNCATE(1.652,1);
/*
mod(a,b): a-a/b*b
mod(-10.-3):-10-(-10)/(-3)*(-3)=-1
*/
#mod 取余
SELECT MOD(3,2);

#日期函数 

#now 返回当前系统日期+时间
SELECT NOW();
#curdate 返回当前系统日期,不包含时间
SELECT CURDATE();
#curTime 返回当前时间,不包含日期
SELECT CURTIME();
#可以获取指定的部分,年、月、日、小时、分钟、秒
SELECT YEAR(NOW())年;
SELECT YEAR('1999-01-01') 年;
SELECT YEAR(hiredate) 年 FROM employees;	
SELECT MONTH(NOW()) 月;
#str_to_date  通过指定的格式将字符转化为日期
SELECT STR_TO_DATE('1998-1-2','%Y-%c-%d') AS out_put;
#查询入职日期为1992-4-3的员工信息
SELECT * FROM employees WHERE hiredate=STR_TO_DATE('4-3 1992','%c-%d %Y');
#date_format 将日期转化为字符
SELECT DATE_FORMAT(NOW(),'%y年%m月%d日') AS out_put;
#查询有奖金的员工姓名和入职日期(xx月/xx日 xx年)
SELECT last_name ,DATE_FORMAT(hiredate,'%m月/%d日 %Y年') 入职日期 FROM employees WHERE commission_pct IS NOT NULL;

# 四,其他函数

SELECT VERSION();
SELECT  DATABASE();
SELECT USER();

# 五、流程控制函数
#1。if 函数: if else 效果

SELECT IF(10>5,'大','小') AS result;

SELECT last_name,commission_pct ,IF(commission_pct IS NOT NULL,'有奖金,嘻嘻','没奖金,哈哈' ) 备注 FROM employees;

#2 case函数的使用 switch case的效果
/*
case 要判断的字段或表达式
when 常量1 then 要显示的值1或语句1;
when 常量2 then 要显示的值2或语句2;
...
else 要显示的值n或语句n
end

*/
/*
案例:查询员工的工资,要求
部门号=30,显示为工资的1.1倍
部门号=40,显示的工资为1.2倍
部门号=50,显示的工资为1.3倍
其他部门,显示的工资为原工资
*/

SELECT salary 原始工资,department_id,
CASE department_id
WHEN 30 THEN salary*1.1
WHEN 40 THEN salary*1.2
WHEN 50 THEN salary*1.3
ELSE  salary
END  AS 新工资
FROM employees;	

#3.case 函数的使用二:类似于 多重if
/*
 case
  when 条件1 then 要显示的值1或语句1;
  when 条件2 then 要显示的值2或语句2;
  ....
  else 要显示的值n或语句n
  ens
  
  
*/

#案例:查询员工的工资情况
/*
如果工资大于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;

#二 分组函数
/*
功能:用作统计使用,又称为聚合函数或者统计函数或组函数
分类:sum avg min max count 计算个数
特点:sum avg一般处理数值型 max min count 可以处理任何类型
      是否忽略null?以上的分组函数都忽略null值
      可以和distinct搭配使用进行去重
      count函数
      和分组函数一同查询的字段要求是group by后的字段

*/
#1 简单的使用
SELECT SUM(salary) FROM employees;
SELECT COUNT(salary) FROM employees;
#2、参数支持类型
SELECT MAX(last_name),MIN(last_name) FROM employees;
# 3 是否忽略null?
SELECT SUM(commission_pct),AVG(commission_pct),SUM(commission_pct)/35,SUM(commission_pct)/107 FROM employees;
# 4和distinct搭配使用
SELECT SUM(DISTINCT salary),SUM(salary) FROM employees;
# 5 count函数的单独介绍
SELECT COUNT(*) FROM employees;
# 6 和分组函数一同查询的字段有限制
SELECT AVG(salary),  employee_id  FROM employees ;
# 查询员工工资的最大值,最小值,平均值,总和
SELECT MIN(salary),MAX(salary),AVG(salary),SUM(salary) FROM employees;
# 查询最大入职时间与最小入职天数之差
SELECT DATEDIFF (MAX(hiredate),MIN(hiredate)) AS difference FROM employees;
#查询部门编号为90的员工个数
SELECT COUNT(*) FROM employees WHERE department_id=90; 

#进阶五:分组查询

# 引入:查询每个部门的平均工资
/*

语法:
select 分组函数,列(要求出现在groupby后面)
from 表名
【where 筛选条件】
grooup by 分组的列表
【order by 子句】
注意:
    查询列表必须是特殊,要求是分组函数和group by 后出现的字段

特点:  
     1 分组查询中筛选条件分为两类
                       数据源不一样     位置                    关键字
     分组前筛选         原始表           group by字句的前面     where
     分组后筛选         分组后的结果集   group by 字句的后面    having
       
     分组函数做条件肯定是放在having字句中
     能用分组前筛选的,就优先考虑使用分组前筛选
     2 group by 字句支持单个字段分组,多个字段分组(多个字段之间用逗号隔开,没有顺序要求)
     表达式或函数(用的较少)
     3 也可以呀添加排序(排序放在整个分组查询的最后)
     


*/
#案例1:查询每个工种的最高工资
SELECT MAX(salary),job_id FROM employees GROUP BY job_id;
#案例2:查询每个位置上的部门个数
SELECT COUNT(*),location_id FROM departments GROUP BY location_id;
#添加筛选条件(分组前的筛选)
#案例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;
#添加复杂的筛选条件(分组后的筛选)
#案例1:查询那个部门的员工个数大于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;
#2案例2:查询每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
SELECT job_id,MAX(salary) FROM employees WHERE commission_pct IS NOT NULL  GROUP BY job_id HAVING MAX(salary)>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;
#案例3:查询领导编号大于102的每个领导手下的最低工资大于5000的领导编号是哪个,以及其最低工资
SELECT manager_id,MIN(salary) FROM employees WHERE manager_id>102 GROUP BY manager_id HAVING MIN(salary)>5000;
#按表达式或函数分组
#案例:按员工姓名的长度分组,查询每一组的员工个数,筛选员工个数大于5的有哪些
SELECT COUNT(*) FROM employees GROUP BY LENGTH(last_name) HAVING COUNT(*)>5;
# 按多个字段分组
#案例:查询每个部门每个工种的员工的平均工资
SELECT AVG(salary),department_id,job_id FROM employees GROUP BY department_id,job_id;
#添加排序
SELECT AVG(salary),department_id,job_id FROM employees GROUP BY department_id,job_id ORDER BY AVG(salary) DESC;
#查询员工最低工资与最高工资的差距
SELECT MAX(salary)-MIN(salary) AS difference FROM employees;

#查询各个管理者手下员工的最低工资,其中最低工资不能滴滴与6000,没有管理者的员工不计算在内
SELECT MIN(salary),manager_id FROM employees WHERE manager_id IS NOT NULL GROUP BY manager_id HAVING MIN(salary)>=6000;

#查询所有部分的编号,员工数量和员工平均工资,并按平均工资降序
SELECT department_id,COUNT(*),AVG(salary) FROM employees GROUP BY department_id ORDER BY AVG(salary) DESC;
#选择具有各个job_id的员工数
SELECT COUNT(*),job_id FROM employees WHERE job_id IS NOT NULL GROUP BY job_id;

连接查询:

#进阶6:连接查询
/*
说明:又称多表查询,当查询语句涉及到的字段来自于多个表时,就会用到连接查询

笛卡尔乘积现象:表1 有m行,表2有n行,结果=m*n行

	发生原因:没有有效的连接条件
	如何避免:添加有效的连接条件

分类:

	按年代分类:
	1、sql92标准:仅仅支持内连接
		内连接:
			等值连接
			非等值连接
			自连接
	2、sql99标准【推荐】:支持内连接+外连接(左外和右外)+交叉连接
	
	按功能分类:
		内连接:
			等值连接
			非等值连接
			自连接
		外连接:
			左外连接
			右外连接
			全外连接
		
		交叉连接


*/
#引入案例
#查询女神名和对应的男神名
SELECT * FROM beauty;

SELECT * FROM boys;


SELECT NAME,boyName FROM boys,beauty
WHERE beauty.boyfriend_id= boys.id;

#---------------------------------sql92标准------------------
#一、内连接
/*
语法:
select 查询列表
from 表1 别名,表2 别名
where 连接条件
and 筛选条件
group by 分组列表
having 分组后筛选
order by 排序列表

执行顺序:

1、from子句
2、where子句
3、and子句
4、group by子句
5、having子句
6、select子句
7、order by子句




*/


#一)等值连接
/*

① 多表等值连接的结果为多表的交集部分
②n表连接,至少需要n-1个连接条件
③ 多表的顺序没有要求
④一般需要为表起别名
⑤可以搭配前面介绍的所有子句使用,比如排序、分组、筛选


*/



#案例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`;



#2、为表起别名
/*
①提高语句的简洁度
②区分多个重名的字段

注意:如果为表起了别名,则查询的字段就不能使用原来的表名去限定

*/
#查询员工名、工种号、工种名

SELECT e.last_name,e.job_id,j.job_title
FROM employees  e,jobs j
WHERE e.`job_id`=j.`job_id`;


#3、两个表的顺序是否可以调换

#查询员工名、工种号、工种名

SELECT e.last_name,e.job_id,j.job_title
FROM jobs j,employees e
WHERE e.`job_id`=j.`job_id`;


#4、可以加筛选


#案例:查询有奖金的员工名、部门名

SELECT last_name,department_name,commission_pct

FROM employees e,departments d
WHERE e.`department_id`=d.`department_id`
AND e.`commission_pct` IS NOT NULL;

#案例2:查询城市名中第二个字符为o的部门名和城市名

SELECT department_name,city
FROM departments d,locations l
WHERE d.`location_id` = l.`location_id`
AND city LIKE '_o%';

#5、可以加分组


#案例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 departments d,employees e
WHERE d.`department_id`=e.`department_id`
AND commission_pct IS NOT NULL
GROUP BY department_name,d.`manager_id`;
#6、可以加排序


#案例:查询每个工种的工种名和员工的个数,并且按员工个数降序

SELECT job_title,COUNT(*)
FROM employees e,jobs j
WHERE e.`job_id`=j.`job_id`
GROUP BY job_title
ORDER BY COUNT(*) DESC;




#7、可以实现三表连接?

#案例:查询员工名、部门名和所在的城市

SELECT last_name,department_name,city
FROM employees e,departments d,locations l
WHERE e.`department_id`=d.`department_id`
AND d.`location_id`=l.`location_id`
AND city LIKE 's%'

ORDER BY department_name DESC;



#二)非等值连接


#案例1:查询员工的工资和工资级别


SELECT salary,grade_level
FROM employees e,job_grades g
WHERE salary BETWEEN g.`lowest_sal` AND g.`highest_sal`
AND g.`grade_level`='A';

/*
select salary,employee_id from employees;
select * from job_grades;
CREATE TABLE job_grades
(grade_level VARCHAR(3),
 lowest_sal  int,
 highest_sal int);

INSERT INTO job_grades
VALUES ('A', 1000, 2999);

INSERT INTO job_grades
VALUES ('B', 3000, 5999);

INSERT INTO job_grades
VALUES('C', 6000, 9999);

INSERT INTO job_grades
VALUES('D', 10000, 14999);

INSERT INTO job_grades
VALUES('E', 15000, 24999);

INSERT INTO job_grades
VALUES('F', 25000, 40000);

*/




#三)自连接



#案例:查询 员工名和上级的名称

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`;



#------------------------SQL99语法
#一、内连接
语法:

SELECT 查询列表
FROM 表名1 别名
【INNER】 JOIN  表名2 别名
ON 连接条件
WHERE 筛选条件
GROUP BY 分组列表
HAVING 分组后筛选
ORDER BY 排序列表;


SQL92和SQL99的区别:

	SQL99,使用JOIN关键字代替了之前的逗号,并且将连接条件和筛选条件进行了分离,提高阅读性!!!



#一)等值连接
#①简单连接
#案例:查询员工名和部门名

SELECT last_name,department_name
FROM departments d 
 JOIN  employees e 
ON e.department_id =d.department_id;



#②添加筛选条件
#案例1:查询部门编号>100的部门名和所在的城市名
SELECT department_name,city
FROM departments d
JOIN locations l
ON d.`location_id` = l.`location_id`
WHERE d.`department_id`>100;


#③添加分组+筛选
#案例1:查询每个城市的部门个数

SELECT COUNT(*) 部门个数,l.`city`
FROM departments d
JOIN locations l
ON d.`location_id`=l.`location_id`
GROUP BY l.`city`;




#④添加分组+筛选+排序
#案例1:查询部门中员工个数>10的部门名,并按员工个数降序

SELECT COUNT(*) 员工个数,d.department_name
FROM employees e
JOIN departments d
ON e.`department_id`=d.`department_id`
GROUP BY d.`department_id`
HAVING 员工个数>10
ORDER BY 员工个数 DESC;







#二)非等值连接

#案例:查询部门编号在10-90之间的员工的工资级别,并按级别进行分组
SELECT * FROM sal_grade;


SELECT COUNT(*) 个数,grade
FROM employees e
JOIN sal_grade g
ON e.`salary` BETWEEN g.`min_salary` AND g.`max_salary`
WHERE e.`department_id` BETWEEN 10 AND 90
GROUP BY g.grade;




#三)自连接

#案例:查询员工名和对应的领导名

SELECT e.`last_name`,m.`last_name`
FROM employees e
JOIN employees m
ON e.`manager_id`=m.`employee_id`;



#二、外连接

/*

说明:查询结果为主表中所有的记录,如果从表有匹配项,则显示匹配项;如果从表没有匹配项,则显示null

应用场景:一般用于查询主表中有但从表没有的记录

特点:

1、外连接分主从表,两表的顺序不能任意调换
2、左连接的话,left join左边为主表
   右连接的话,right join右边为主表
   

语法:

select 查询列表
from 表1 别名
left|right|full 【outer】 join 表2 别名
on 连接条件
where 筛选条件;

*/
USE girls;
#案例1:查询所有女神记录,以及对应的男神名,如果没有对应的男神,则显示为null

#左连接
SELECT b.*,bo.*
FROM beauty b
LEFT JOIN boys bo ON b.`boyfriend_id` = bo.`id`;

#右连接
SELECT b.*,bo.*
FROM boys bo
RIGHT JOIN  beauty b ON b.`boyfriend_id` = bo.`id`;







#案例2:查哪个女神没有男朋友

#左连接
SELECT b.`name`
FROM beauty b
LEFT JOIN boys bo ON b.`boyfriend_id` = bo.`id`
WHERE bo.`id`  IS NULL;

#右连接
SELECT b.*,bo.*
FROM boys bo
RIGHT JOIN  beauty b ON b.`boyfriend_id` = bo.`id`
WHERE bo.`id`  IS NULL;


#案例3:查询哪个部门没有员工,并显示其部门编号和部门名

SELECT COUNT(*) 部门个数
FROM departments d
LEFT JOIN employees e ON d.`department_id` = e.`department_id`
WHERE e.`employee_id` IS NULL;



















知识点:

排序查询:

一:语法

  select 查询列表

  from 表

 where 筛选条件

order by 排序列表

二、特点:

1.asc:升序,如果不写默认升序 desc:降序

2.排序列表:支持 单个字段、多个字段、函数、表达式、别名

3.order by的位置,一般放在查询语句的最后(除limit语句之外)

常见函数

一、概述

功能:类似于java中的方法。好处:提高重用性和隐藏实现细节 调用:select  函数名(实参列表)

二、单行函数

1.字符函数

concat 连接函数 substr:截取子串 upper:变大写 lower:变小写 replace:替换 length:获取字节长度

trim:去掉前后空格 lpad左填充 rpad右填充 instr:获取子串第一次出现的索引

2.数学函数

ceil :向上取整、round:四舍五入 mod:取模 floor:向下取整 truncate:截断 rand:获取随机数,返回0-1之间的小数

3.日期函数

now:返回当前日期+时间 year:返回年 month day hour  date_format:将日期转化为字符 curdate:返回当前日期,str_to_date:将字符转化为日期 curTime:返回当前时间 datediff:返回两个日期相差的天数 monthname:以英文的形式返回月

4.其他函数

version:当前数据库服务器的版本 database:当前打开的数据库 user:当前用户 password('''字符')返回该字符的密码形式,自动加密。md5(''字符'') MD5加密

5.流程控制函数

if(条件表达式,表达式1,表达式2):如果条件表达式成立,返回表达式1,否则返回表达式2

case情况1:

case 表达式或变量或字段

   when 常量1 then 值1

   when  常量2 then 值2

   ....

   else 值 n

   end

case情况2:

case 

   when 条件1 then 值1

   when  条件2 then 值2

   ....

   else 值 n

   end

三:分组函数

1、分类

max:最大值 min:最小值 sum:求和 avg:平均值 count:计算个数

2.特点:

语法:select min(字段) from 表名

支持的类型:sum和avg一般用于处理数值型 max\min\count 可以处理任何数据类型

以上分组函数都忽略null值 都可以搭配distinct关键字来实现去重的功能

select max(distinct 字段) from  表名

count函数: count(字段) 统计该字段非空值的个数 count(*) 统计结果集的行数 count(1) 用于统计结果集的行数。效率上:MyISAM存储引擎:count(*)最高,InnoDB存储引擎:count(*)和count(1)大于count(字段)

和分组函数一同查询的字段,要求是group by后出现的字段

分组查询:

一、语法

select 分组函数,分组后的字段

from  表

【where 筛选条件】

group by 分组的字段

having 分组后的筛选

【order by 排序后的字段】

二、特点

                        使用关键字         筛选的表      位置

分组前筛选         where               原始表       group by的前面

分组后筛选         having        分组后的结果  group by的后面

连接查询

一、含义

    当查询中涉及到了多个表的字段,需要使用多表连接

select 字段1,字段2

from 表1,表2

笛卡尔乘积:当查询多个表时,没有添加有效的连接条件,导致多个表的所用行实现完全连接

如何解决?添加有效的连接条件

二、分类

按年代分类 SQL92:等值连接、非等值、自连接。也支持一部分外连接(oracle

sqlServer)SQL99:内连接(等值、非等值、自连接)、外连接(左外、右外、全外)、交叉连接

三、SQL92语法

1、等值连接

语法:select 查询列表

          from 表1 别名,表2 别名

         where  表1.key=表2.key

          [ and 筛选条件]

         【group by 分组字段】

        【having 分组后的筛选】

          【order by 排序字段】

特点:一般为表起别名、多表的顺序可以调换、n表连接至少需要n-1个连接条件、等值连接的结果是多表连接的交集部分

2、非等值连接

语法:select 查询列表

          from 表1 别名,表2 别名

         where  非等值的连接条件

          [ and 筛选条件]

         【group by 分组字段】

        【having 分组后的筛选】

          【order by 排序字段】

#案例1:查询员工的工资和工资级别
SELECT salary,grade_level
FROM employees e,job_grades g
WHERE salary BETWEEN g.`lowest_sal` AND g.`highest_sal`
AND g.`grade_level`='A';

3、自连接

语法:select 查询列表

          from 表 别名1,表 别名2

         where 等值的连接条件

          [ and 筛选条件]

         【group by 分组字段】

        【having 分组后的筛选】

          【order by 排序字段】

#3.自连接
#案例:查询员工名和上级的名称
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`;

四、SQL99语法

1、内连接

语法:

select   查询列表 

from 表1 别名

【inner join】 表2  别名 on 连接条件

where  筛选条件

group by 分组列表

having 分组后的筛选

order by 排序列表

limit  字句;

特点:

表的顺序可以调换,内连接的结果=多表的交集;n表连接至少需要n-1个连接条件

分类:等值连接、非等值连接、自连接

2、外连接

语法:

select   查询列表 

from 表1 别名

left|right|full【outer】 join 表2  别名 on 连接条件

where  筛选条件

group by 分组列表

having 分组后的筛选

order by 排序列表

limit  字句;

特点:查询的结果=主表中的所有的行,其中从表和它匹配的将显示匹配行,如果从表没有匹配的则显示null。left join 左边的是主表,right join 右边的是主表 full join 两边都是主表。一般用于查询交集部分,剩余的不匹配的行

3、交叉连接

语法:

select 查询列表

from 表1 别名

cross join 表2 别名;

特点:类似于生成笛卡尔乘积

子查询

一、含义

嵌套在其他语句内部的select语句称为子查询或者内查询。外面的语句可以是insert\update\delete\select等,一般select作为外面的语句较多。外面如果为select语句,则称为外查询或者主查询此语句

二、分类

1、按出现位置

select后面

    仅仅支持变量子查询

from 后面

      表子查询

where或having后面

         标量子查询

         列子查询

         行子查询

exists后面

          标量子查询

           列子查询

           行子查询

            表子查询

           

2、按结果集的行列

标量子查询(单行子查询):结果集为一行一列

列子查询(多行子查询):结果集为多行一列

行子查询:结果集为多行多列

表子查询:结果集为多行多列

三、示例

where或having后面

1.标量子查询

查询最低工资的员工姓名和工资

select last_name,salary from employees where salary=(seelct min(salary from employees));

2.列子查询

查询所有是领导的员工姓名

select last_name from employes where employee_id in (select manager_id from employees);

分页查询

一、应用场景

当要查询的条目数太多,一页显示不全

二、语法

select 查询列表

from 表

limit [offset,] size;

注意:offset代表的是起始条目的索引,默认是从0开始

size代表的是显示的条目数

公式:假如要显示的页数为page,每一页的条数目为size

select 查询列表

from 表

limit [page-1]*size size;

# SQL99语法
/*
语法:
      select 查询列表
      from 表1 别名 【连接类型】
      join 表2 别名 
      on 连接条件
      【where 筛选条件】
      【group by 分组】
      【having 筛选条件】
      【order by 排序列表】
内连接:inner
外连接: 左外 left 【outer】右外 right 【outer】 全外 full【outer】
交叉连接: cross
*/

#-)内连接
/*
语法:
select 查询列表
from 表1 别名
inner join 表2 别名
on  连接条件

分类:等值连接、非等值连接 自连接
特点:添加排序、分组、筛选;inner可以省略;筛选条件放在where后面,连接条件放在on后面
      inner join 连接和SQL92语法中的等值连接效果是一样的,都是查询多表的交集部分
*/
#1 等值连接

#案例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(*) FROM locations l INNER JOIN departments d 
ON l.`location_id`=d.`location_id` GROUP BY city  HAVING COUNT(*)>3;

#案例4:查询那部门的员工数大3的部门名和员工个数。并按个数降序
SELECT department_name,COUNT(*) 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 INNER JOIN jobs j ON
j.`job_id`=e.`job_id` AND e.`department_id`=d.`department_id` ORDER BY department_name DESC;

#2 非等值连接
#查询员工的工资级别
SELECT j.`grade_level` ,salary FROM employees e INNER JOIN job_grades j ON e.`salary` BETWEEN j.`lowest_sal` AND j.`highest_sal`;
# 查询每个工资基本的个数
SELECT j.`grade_level` ,COUNT(*) FROM employees e INNER JOIN job_grades j ON e.`salary` BETWEEN j.`lowest_sal` AND j.`highest_sal`
GROUP BY j.`grade_level` ORDER BY j.`grade_level` DESC;

#自连接
#案例:查询员工的名字和上级的名字
SELECT e.last_name ,m.last_name FROM employees e INNER JOIN employees m ON m.`employee_id`=e.`manager_id`;


#外连接
/*
应用情景:一般用于查询一个表中有,另外一个表中没有的记录
特点:
     1.外连接的查询结果为主表中的所有记录,如果从表中有与它匹配的,则显示匹配的列值
     如果从表中没有与它匹配的,则显示null
     外连接查询结果=内连接结果+主表中有从表中没有的记录
     2 左外连接 :left join 左边的是主表 右外连接: right join右边的是主表  
     3 左外与右外交换两个表的顺序,可以实现同样的效果
     4 全外连接=内连接的结果+表1中有但表2中没有+表2中有但表1中没有
*/
# 引入:查询没有男朋友的女神名

SELECT g.name FROM boys b RIGHT JOIN beauty g ON g.`boyfriend_id`=b.`id` WHERE  b.`id` IS NULL;

#案例:查询那个部门没有员工
#左外 部门表是主表
SELECT department_name,e.`employee_id`FROM departments d LEFT JOIN employees e
ON d.`department_id`= e.`department_id` WHERE e.`employee_id` IS NULL;

#全外
USE girls;
SELECT b.*,boys.* FROM beauty b FULL OUTER JOIN boys   ON b.`boyfriend_id`= boys.`id`; 

#交叉连接
SELECT b.*,bo.* FROM beauty b CROSS JOIN boys bo ;

#SQL92和SQL99大PK
功能:sql99支持的较多
可读性:sql99实现连接条件和筛选条件的分离,可读性较高


表的连接总结

 

#进阶查询:子查询
/*
含义:出现在其他语句中的select语句,称为子查询或内查询
外部的查询语句称为主查询或者外查询
分类:
按子查询出现的位置:
        select后面
              仅仅支持标量子查询
        from 后面
              支持表子查询
        where或having后面★
              标量子查询(单行)
              列子查询 (多行)
              行子查询(用的较少)
        exists后面(相关子查询)
              表子查询
按结果集的行列数不同:
       标量子查询(结果集只有一行一列)
       列子查询(结果集只有一列多行)
       行子查询(结果集有一行多列)
       表子查询(结果集一般有多行多列)
             

*/

#一、where或having后面
/*
1.标量子查询(单行子查询)
2.列子查询(多行子查询)

3.行子查询
特点
子查询放在小括号内,子查询一般放在条件的右侧,标量子查询,一般搭配着单行操作符使用(> < >= <= =)
列子查询:一般搭配着多行操作符使用 IN ANY、some  ALL
子查询的执行优先于主查询的执行,主查询的条件用到了子查询的结果
*/
#1.标量子查询
#案例1:谁的工资比Abel高?
SELECT *  FROM employees WHERE salary>(
SELECT salary FROM employees WHERE last_name="Abel");

#案例2:返回job_id与141号员工相同,salary比143号员工多的员工姓名,job_id 和工资

SELECT last_name,job_id,salary FROM employees WHERE job_id=(
SELECT job_id FROM employees WHERE employees.`employee_id`=141) AND
salary>(SELECT salary FROM  employees WHERE employees.`employee_id`=143);

#案例3: 返回公司工资最少的员工的last_name,job_id和salary
SELECT last_name ,job_id,salary FROM employees WHERE salary=(
SELECT MIN(salary) FROM employees);

#案例4:查询最低工资大于50号部门最低工资的部门id和其最低工资
SELECT MIN(salary),department_id FROM   employees  GROUP  BY department_id HAVING MIN(salary)>(SELECT MIN(salary)
FROM employees WHERE employees.`department_id`=50);

#2.列子查询 (多行子查询)
#案例1:返回location_id是1400或1700的部门中的所有员工姓名
SELECT last_name FROM employees WHERE department_id IN(SELECT DISTINCT department_id FROM departments WHERE location_id IN(1400,1700) );

#案例2:返回其它部门中比job_id为‘IT_PROG’部门任一工资低的员工的员
#              工号、姓名、job_id 以及salary

SELECT employee_id,last_name,job_id,salary FROM employees WHERE salary <ANY(
SELECT DISTINCT salary FROM employees WHERE job_id="IT_PROG") AND job_id <> "IT_PROG";

SELECT employee_id,last_name,job_id,salary FROM employees WHERE salary <(
SELECT MAX(salary) FROM employees WHERE job_id="IT_PROG") AND job_id <> "IT_PROG";

#案例3:返回其它部门中比job_id为‘IT_PROG’部门所有工资都低的员工
 #           的员工号、姓名、job_id 以及salary
 
 SELECT employee_id,last_name,job_id,salary FROM employees WHERE salary < ALL(
 SELECT MIN(salary) FROM employees WHERE job_id="IT_PROG") AND job_id <> "IT_ROUTE";
# 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);


#二、select后面
/*
 仅仅支持标量子查询
*/
#案例:查询每个部门的员工个数
SELECT d.*,(
 SELECT COUNT(*) FROM employees  e
 WHERE e.department_id=d.`department_id`
   ) 个数
FROM departments d;   

#案例2:查询员工号=102的部门名
SELECT department_name FROM  departments d LEFT JOIN employees e ON d.`department_id`=e.`department_id` WHERE
e.`employee_id`=102;

SELECT( SELECT department_name FROM departments d INNER JOIN employees e ON d.department_id=e.department_id WHERE e.employee_id="102");

#三:将子查询放在from后面

/*
将子查询的结果充当一张表,要求必须起别名
*/
#案例:查询每个部门的平均工资的工资等级

SELECT ag_dep.*, j.`grade_level`
FROM (
SELECT AVG(salary) ag,department_id FROM employees GROUP BY department_id
) ag_dep INNER JOIN job_grades j ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;

#四、exists 后面 (相关子查询)

/*
语法:exists(完整的查询语句)
结果:1或0
*/
#案例1:查询有员工的部门名
SELECT department_name FROM departments d
WHERE EXISTS (
SELECT * FROM employees e WHERE e.`department_id`=d.`department_id`
);
SELECT department_name FROM departments d WHERE d.department_id IN(
SELECT department_id FROM employees );

子查询练习:

#1. 查询和 Zlotkey 相同部门的员工姓名和工资

SELECT last_name,salary FROM employees WHERE department_id =(
SELECT department_id FROM employees WHERE last_name="Zlotkey");

#2. 查询工资比公司平均工资高的员工的员工号,姓名和工资。
SELECT employee_id,last_name,salary
FROM employees WHERE salary>(
SELECT AVG(salary) FROM employees 
) ;
#3. 查询各部门中工资比本部门平均工资高的员工的员工号, 姓名和工资
SELECT last_name,employee_id,salary 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;

#4. 查询和姓名中包含字母 u 的员工在相同部门的员工的员工号和姓名
SELECT employee_id,last_name FROM employees WHERE department_id IN (
SELECT  DISTINCT department_id FROM employees WHERE last_name LIKE "%u%");
#5. 查询在部门的 location_id 为 1700 的部门工作的员工的员工号
SELECT employee_id FROM employees WHERE department_id IN (SELECT department_id FROM departments
WHERE location_id=1700);
#6. 查询管理者是 King 的员工姓名和工资
SELECT last_name,salary FROM employees WHERE manager_id= ANY(SELECT employee_id FROM employees WHERE last_name="K_ing");
#7. 查询工资最高的员工的姓名,要求 first_name 和 last_name 显示为一列,列名为 姓.名
SELECT CONCAT(last_name,first_name) AS '姓.名' FROM employees WHERE  salary =(SELECT MAX(salary)
FROM employees);

案例练习:


#1. 查询工资最低的员工信息: last_name, salary
SELECT last_name,salary FROM employees WHERE salary=(SELECT MIN(salary) FROM employees);

#2. 查询平均工资最低的部门信息

SELECT 
  d.* 
FROM
  departments d 
  LEFT JOIN 
    (SELECT 
      department_id,
      AVG(salary) AS avs 
    FROM
      employees 
    GROUP BY department_id 
    ORDER BY avs ASC 
    LIMIT 1) ag 
    ON d.`department_id` = ag.department_id 
WHERE ag.avs IS NOT NULL ;

#3. 查询平均工资最低的部门信息和该部门的平均工资

SELECT 
  * 
FROM
  departments d 
  LEFT JOIN 
    (SELECT 
      department_id,
      AVG(salary) AS avs 
    FROM
      employees 
    GROUP BY department_id 
    ORDER BY avs ASC 
    LIMIT 1) ag 
    ON d.`department_id` = ag.department_id 
WHERE ag.avs IS NOT NULL ;

#4. 查询平均工资最高的 job 信息
SELECT 
  j.* 
FROM
  jobs j 
  LEFT JOIN 
    (SELECT 
      job_id,
      AVG(salary) ag 
    FROM
      employees 
    GROUP BY job_id 
    ORDER BY ag DESC 
    LIMIT 1) e 
    ON e.job_id = j.`job_id` 
WHERE ag IS NOT NULL ;

#5. 查询平均工资高于公司平均工资的部门有哪些?
SELECT 
  e.department_id 
FROM
  (SELECT 
    department_id,
    AVG(salary) ag 
  FROM
    employees 
  GROUP BY department_id) e 
WHERE e.ag > 
  (SELECT 
    AVG(salary) 
  FROM
    employees) 
  AND e.department_id IS NOT NULL ;

#6. 查询出公司中所有 manager 的详细信息.
SELECT 
  * 
FROM
  employees 
WHERE employee_id IN 
  (SELECT DISTINCT 
    manager_id 
  FROM
    employees) ;

#7. 各个部门中 最高工资中最低的那个部门的 最低工资是多少
SELECT 
  MIN(salary) 
FROM
  employees 
WHERE department_id = 
  (SELECT 
    department_id 
  FROM
    employees 
  GROUP BY department_id 
  ORDER BY MAX(salary) 
  LIMIT 1) ;

#8. 查询平均工资最高的部门的 manager 的详细信息: last_name, department_id, email, salary

SELECT 
  last_name,
  department_id,
  email,
  salary 
FROM
  employees 
WHERE employee_id IN 
  (SELECT 
    manager_id 
  FROM
    departments d 
    INNER JOIN 
      (SELECT 
        AVG(salary) ag,
        department_id 
      FROM
        employees 
      GROUP BY department_id 
      ORDER BY ag DESC 
      LIMIT 1) e 
      ON d.department_id = e.department_id ) ;

#1 查询每个专业的学生数
SELECT COUNT(*),majorid FROM stuinfo GROUP BY majorid;
#查询参加考试的学生中,每个学生的平均分、最高分
SELECT AVG(score),MAX(score) FROM result r INNER JOIN student s
ON s.`studentno`=r.`studentno` GROUP BY r.`studentno`; 
#查询姓张的每个学生的最低分大于60的学号、姓名
SELECT s.studentno,s.studentname,MIN(score)
FROM student s INNER JOIN result r
ON s.`studentno`=r.`studentno`
WHERE s.`studentname` LIKE "张%"
GROUP BY s.`studentno`
HAVING MIN(score)>60;
#查询每个专业生日在1998-1-1后的学生姓名、专业名称
SELECT s.studentname,m.majorname FROM (SELECT * FROM student  WHERE borndate>"1998-1-1" GROUP BY majorid
) s
INNER JOIN major m ON s.majorid=m.`majorid`;

#查询每个专业的男生和女生人数
SELECT COUNT(*),sex,majorid FROM student GROUP BY sex,majorid;
#查询专业和张翠山一样1学生的最低分
SELECT MIN(score) FROM result WHERE studentno IN(
SELECT studentno FROM student  WHERE majorid=(SELECT majorid FROM student
WHERE studentname="张翠山") );
#查询大于60分的学生的姓名、电环号码、专业名
SELECT s.studentname,s.phone,m.majorname FROM student s
INNER JOIN result r INNER JOIN major m ON s.`majorid`=m.`majorid`AND s.`studentno`=r.`studentno` WHERE r.`score`>60

#按照邮箱的维数分组,查询每组的学生个数
SELECT COUNT(*) FROM student GROUP BY LENGTH(email);
#查询学生名、专业名、分数
SELECT m.majorname,s.studentname,r.score
FROM student s INNER JOIN result r INNER JOIN major m
ON r.`studentno`=s.`studentno` AND s.`majorid`=m.`majorid`; 
#查询哪个专业没有学生
SELECT * FROM major LEFT JOIN student ON major.`majorid`=student.`majorid` WHERE student.`studentno` IS NULL;

SELECT * FROM student RIGHT JOIN major ON major.`majorid`=student.`majorid` WHERE student.`studentno` IS NULL;

#查询没有成绩学生人数
SELECT COUNT(*) FROM student  LEFT JOIN result ON student.`studentno`=result.`studentno` WHERE score IS NULL;

联合查询:

#进阶9:联合查询
/*
union 联合 合并:将多条查询语句的结果合并成一个结果

语法:
查询语句1
union
查询语句2
union
....
应用场景:
要查询的结果来自于多个表,且多个表没有直接的连接关系
但查询的信息一致

特点:
1.要求多条查询语句的查询列数是一致的
2.要求多条查询语句的查询的每一列的类型和顺序最好一致
3.union关键字默认是去重的,如果使用union all 可以包含重复项
*/

#引入案例:查询部门编号大于90或邮箱包含a的员工信息

SELECT * FROM employees WHERE email LIKE '%a%' OR department_id >90;

SELECT * FROM employees WHERE email LIKE '%a%'
UNION
SELECT * FROM employees WHERE department_id>90;
#查询中国用户中男性的信息以及外国用户中男性的信息
SELECT id,cname,csex FROM  t_ca WHERE csex='男'
UNION 
SELECT t_id,tName,tGender FROM t_ua WHERE tGender='male';

DML语言

#DML语言
/*
数据操作语言:
插入:insert
修改:update
删除:delete

*/

# 一、插入语句
/*
插入语句:
 语法:
  insert into 表名(列名....)values(值1,...)
  
*/
SELECT * FROM beauty; 
#1.插入值的类型要与列的类型一致或兼容
INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id)
VALUES(13,'唐艺昕','女','1990-07-23','18211121311',NULL,2);
#2 不可以为null的列是必须插入值的,可以为null的列是如何插入值的
#方式1:

INSERT INTO beauty(id,NAME,sex,borndate,phone,photo,boyfriend_id)
VALUES(13,'唐艺昕','女','1990-07-23','18211121311',NULL,2);

#方式2:
INSERT INTO beauty(id,NAME,sex,borndate,phone,boyfriend_id)
VALUES(14,'行单','女','1910-07-23','18211121311',2);

#3.列的顺序是否可以调换
INSERT  INTO beauty(NAME,sex,id,phone)VALUES('范冰冰','女',15,'128277726253');

#4.列的个数和值的个数,必须是一致的
#5.可以省略列名,默认是所有列,而且列的顺序与表中的顺序是一致的
INSERT INTO beauty VALUES (16,'张飞','男',NULL,'119',NULL,NULL);

#方式二:
/*
语法:
insert into 表名
set 列名=值,列名=值,...
*/
INSERT INTO beauty 
SET id=19,
NAME='刘涛',
phone='999';

#两种方式大PK
1.方式1:支持插入多行,方式二不支持
INSERT INTO beauty
VALUES(20,'唐艺昕','女','1990-07-23','18211121311',NULL,2),
(21,'唐艺昕','女','1990-07-23','18211121311',NULL,2),
(22,'唐艺昕','女','1990-07-23','18211121311',NULL,2);
2.方式1支持子查询,方式2不支持
INSERT INTO  beauty(id,NAME,phone)
SELECT 23,'宋阿西','19391';

#二、修改语句
/*
语法:
1.修改单表的记录
语法:
update 表名
set 列=新值,列=新值,...
where 筛选条件

2.修改多表的记录
语法:
SQL92:
update 表1 别名,表2 别名
set  列=值
where 连接条件
and 筛选条件
SQL99:
update 表1 别名
inner|left|right join  表2 别名
on 连接条件
set  列=值 ...
where 筛选条件;


*/

#1.修改单表的记录
#1.案例:修改beauty表中姓唐的女神的电话为13822222
UPDATE beauty SET phone='13819822212' WHERE NAME LIKE '唐%';

#2:案例:修改boys表中的id号为2的名称为张飞,魅力值为10
UPDATE boys SET boyname='张飞',usercp=10
WHERE id=2;

#2 修改多表的记录
#案例1:修改张无忌的女朋友的手机号为114
UPDATE boys bo INNER JOIN beauty b ON bo.`id`=b.`boyfriend_id`
SET b.`phone`='114' WHERE bo.`boyName`='张无忌';

#案例2:修改没有男朋友的女神的的男朋友编号为2
UPDATE boys bo RIGHT JOIN beauty b ON bo.`id`=b.`boyfriend_id`
SET b.`boyfriend_id`=2 WHERE b.id IS NULL;

#三、删除语句
/*
方式1:delete
语法:
1.单表的删除 
delete from 表名 where 筛选条件
2.多表的删除
SQL92:
delete 表1的别名,表2的别名
from 表1 别名,表2 别名
where 连接条件
and 筛选条件;
SQL99:
 delete 表1的别名,表2的别名
 from 表1 别名
 inner|left|right join 表2 别名 on 连接条件
 where 筛选条件;

方式2:truncate
语法:truncate table 表名;
*/
#方式1:delete
#1.实现单表的删除
#案例1:删除手机号以9结尾的女神信息
DELETE FROM beauty WHERE phone LIKE '%9';

#多表的删除
#案例:删除张无忌的女神的信息
DELETE b
FROM beauty b INNER JOIN boys bo
ON b.`boyfriend_id`=bo.`id`
WHERE bo.`boyName`='张无忌';
#案例:删除黄晓明的信息以及他女朋友的信息
DELETE bo,b FROM beauty b INNER JOIN boys bo ON
b.`boyfriend_id`=bo.`id` WHERE bo.`boyName`='黄晓明';

#方式2:truncate语句
#案例:将魅力值大于100的男神删除
TRUNCATE TABLE boys ;

#delete pk truncate

1.delete 可以添加WHERE条件,TRUNCATE不可以的
2.truncate的删除,效率高一丢丢
3.假如要删除表中的有自增长的列
如果用DELETE删除后,再插入数据,自增长的列的值从断点开始
而TRUNCATE删除后,再插入数据,自增长的列的值从1开始
4.truncate删除没有返回值,DELETE删除是有返回值的
5.truncate删除不能回滚,delete删除可以回滚

DDL 数据定义语言

DDL
/*
数据定义语言:
库和表的管理
一、库的管理
创建、修改、删除
二、表的管理
创建、修改、删除
创建:create
修改:alter
删除:drop
*/
#一、库的管理
#1.库的创建
/*
语法:create database if not exists 库名;
*/
#案例:创建库books
CREATE DATABASE  IF NOT EXISTS books ;
#2.库的修改
更改库的字符集
ALTER DATABASE books CHARACTER SET  gbk;
#3 库的删除
DROP DATABASE IF EXISTS books;

#二、 表的管理
#1 表的创建
/*
create table 表名(
   列名 列的类型【(长度) 约束】,
   列名 列的类型【(长度) 约束】,
   列名 列的类型【(长度) 约束】,
    .....
   列名 列的类型【(长度) 约束】
)


*/

#案例:创建表Book
CREATE TABLE book(
  id INT,
  bname VARCHAR(20),
  price  DOUBLE,
  authorId INT,
  publishDate DATETIME
);

DESC book;

#案例:创建作者表
CREATE TABLE IF NOT EXISTS author(
 id INT,
 au_name VARCHAR(20),
 nation VARCHAR(10)
);

#2 表的修改
#修改列名、列的类型或约束、添加列、删除列、修改表名

/*
语法:
 alter table 表名 add|drop|modify|change column 列名 【列的类型 约束】;
*/
ALTER TABLE book CHANGE COLUMN publishDate pubDate DATETIME;

ALTER TABLE book MODIFY COLUMN pubdate TIMESTAMP;

ALTER TABLE author ADD COLUMN annual DOUBLE;

ALTER TABLE author DROP COLUMN annual;

ALTER TABLE author RENAME TO AUTHORS;


DESC AUTHORS;

#3 表的删除

DROP TABLE IF EXISTS  AUTHORS;

SHOW TABLES;
#通用的写法
DROP DATABASE IF EXISTS 旧库名;
CREATE  DATABASE 新库名;

DROP TABLE IF EXISTS 旧表名;
CREATE TABLE 新表名();

#表的复制

INSERT  INTO author VALUES (1,'村上春树','日本'),
                      (2,'鹿鼎记','金庸'),
                       (3,'小李飞刀','古龙');
                       
#1 仅仅复制表的结构
CREATE TABLE copy LIKE author;

SELECT * FROM copy;  
# 2 复制表的结构+数据
CREATE TABLE copy2 
SELECT * FROM author


SELECT * FROM copy2;  

#只复制部门表的内容,可以加条件限制

#仅仅复制某些数据
CREATE TABLE copy3
SELECT id,nation
FROM author
WHERE 0;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值