数据库的学习(下)

 DQL语言

一、基础查询

语法:
select 查询列表 from 表名;

类似于:System.out.println(打印东西);

特点:

1、查询列表可以是:表中的字段、常量值、表达式、函数
2、查询的结果是一个虚拟的表格

例子

1.查询表中的单个字段

SELECT last_name FROM employees;

2.查询表中的多个字段

SELECT last_name,salary,email FROM employees;

3.查询表中的所有字段

方式一:

SELECT 
    `employee_id`,
    `first_name`,
    `last_name`,
    `phone_number`,
    `last_name`,
    `job_id`,
    `phone_number`,
    `job_id`,
    `salary`,
    `commission_pct`,
    `manager_id`,
    `department_id`,
    `hiredate` 
FROM
    employees ;

方式二:

 SELECT * FROM employees;

4.查询常量值

 SELECT 100;
 SELECT 'john';

5.查询表达式

 SELECT 100%98;

6.查询函数

 SELECT VERSION();

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;

8.去重

案例:查询员工表中涉及到的所有的部门编号

SELECT DISTINCT department_id FROM employees;

9.+号的作用

java中的+号:
①运算符,两个操作数都为数值型
②连接符,只要有一个操作数为字符串

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;

二、条件查询

语法:
	select 
		查询列表
	from
		表名
	where
		筛选条件;

分类:

一、按条件表达式筛选

    简单条件运算符:> < = != <> >= <=

案例1:查询工资>12000的员工信息

SELECT 
	*
FROM
	employees
WHERE
	salary>12000;

案例2:查询部门编号不等于90号的员工名和部门编号

SELECT 
	last_name,
	department_id
FROM
	employees
WHERE
	department_id<>90;

二、按逻辑表达式筛选

        逻辑运算符:
        作用:用于连接条件表达式
        && || !
        and or not
        
    &&和and:两个条件都为true,结果为true,反之为false
    ||或or: 只要有一个条件为true,结果为true,反之为false
    !或not: 如果连接的条件本身为false,结果为true,反之为false

案例1:查询工资z在10000到20000之间的员工名、工资以及奖金

SELECT
	last_name,
	salary,
	commission_pct
FROM
	employees
WHERE
	salary>=10000 AND salary<=20000;

案例2:查询部门编号不是在90到110之间,或者工资高于15000的员工信息

SELECT
	*
FROM
	employees
WHERE
	NOT(department_id>=90 AND  department_id<=110) OR salary>15000;

三、模糊查询

   1. like

特点:
①一般和通配符搭配使用
    通配符:
    % 任意多个字符,包含0个字符
    _ 任意单个字符

案例1:查询员工名中包含字符a的员工信息

select 
	*
from
	employees
where
	last_name like '%a%';#abc

案例2:查询员工名中第三个字符为e,第五个字符为a的员工名和工资

select
	last_name,
	salary
FROM
	employees
WHERE
	last_name LIKE '__n_l%';


2. between and

①使用between and 可以提高语句的简洁度
②包含临界值
③两个临界值不要调换顺序

案例1:查询员工编号在100到120之间的员工信息

SELECT
	*
FROM
	employees
WHERE
	employee_id >= 120 AND employee_id<=100;
#----------------------
SELECT
	*
FROM
	employees
WHERE
	employee_id BETWEEN 120 AND 100;


  3. in

含义:判断某字段的值是否属于in列表中的某一项
特点:
    ①使用in提高语句简洁度
    ②in列表的值类型必须一致或兼容
    ③in列表中不支持通配符

例:查询员工的工种编号是 IT_PROG、AD_VP、AD_PRES中的一个员工名和工种编号

SELECT
	last_name,
	job_id
FROM
	employees
WHERE
	job_id = 'IT_PROT' OR job_id = 'AD_VP' OR JOB_ID ='AD_PRES';


#------------------

SELECT
	last_name,
	job_id
FROM
	employees
WHERE
	job_id IN( 'IT_PROT' ,'AD_VP','AD_PRES');


 4. is null | is not null

=或<>不能用于判断null值
is null或is not null 可以判断null值

案例1:查询没有奖金的员工名和奖金率

SELECT
	last_name,
	commission_pct
FROM
	employees
WHERE
	commission_pct IS NULL;

案例2:查询工资为12000的员工信息

SELECT
	last_name,
	salary
FROM
	employees

WHERE 
	salary <=> 12000;

is null pk <=>

IS NULL:仅仅可以判断NULL值,可读性较高,建议使用
<=>    :既可以判断NULL值,又可以判断普通的数值,可读性较低

三、排序查询

语法:
select 查询列表
from 表名
【where  筛选条件】
order by 排序的字段或表达式;

特点:
1、asc代表的是升序,可以省略
desc代表的是降序

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 employee_id DESC;

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 年薪 ASC;

5、按函数排序
案例:查询员工名,并且按名字的长度降序

SELECT LENGTH(last_name),last_name 
FROM employees
ORDER BY LENGTH(last_name) DESC;

6、按多个字段排序

案例:查询员工信息,要求先按工资降序,再按employee_id升序

SELECT *
FROM employees
ORDER BY salary DESC,employee_id ASC;

四、常见函数

概念:类似于java的方法,将一组逻辑语句封装在方法体中,对外暴露方法名
好处:1、隐藏了实现细节  2、提高代码的重用性
调用:select 函数名(实参列表) 【from 表】;
特点:
    ①叫什么(函数名)
    ②干什么(函数功能)

分类:
    1、单行函数
    如 concat、length、ifnull等
    2、分组函数
    
    功能:做统计使用,又称为统计函数、聚合函数、组函数

 

常见函数:


1、单行函数

      1.1.字符函数:


    length: 获取字节个数    

SELECT LENGTH('john');
SELECT LENGTH('张三丰hahaha');

 concat: 拼接

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

substr: 截取子串

#注意:索引从1开始!!!
#截取从指定索引处后面所有字符
SELECT SUBSTR('李莫愁爱上了路展元',7) out_put;

#截取从指定索引处指定字符长度的字符
SELECT SUBSTRING('李莫愁爱上了路展元',1,3) out_put;

#案例:姓名中首个字符大写,其他字符小写然后用_拼接,显示出来

SELECT CONCAT(UPPER(SUBSTR(last_name,1,1)),'_',LOWER(SUBSTR(last_name,2))) out_put
FROM employees;

 instr: 返回子串第一次出现的索引

返回字串第一次索引,如果找不到返回0
SELECT INSTR('杨不悔爱上了殷六侠','殷六侠') AS out_put;

trim: 去前后指定的空格和字符
    upper: 转换成大写        lower: 转换成小写

SELECT UPPER('john');
SELECT LOWER('joHN');
#实例:将姓变为大写,名变为小写,然后拼接
SELECT CONCAT(UPPER(last_name),LOWER(first_name)) 姓名 FROM employees;

 lpad: 左填充,用指定的字符实现左填充指定长度

SELECT LPAD('殷素素',10,'*') AS out_put;

 rpad: 右填充,用指定的字符实现右填充指定长度

SELECT RPAD('殷素素',12,'*') AS out_put;

replace: 替换

SELECT REPLACE('奈白是方片K','奈白','方片K') AS out_put;

1.2.数学函数:


    round: 四舍五入

SELECT ROUND(1.67);#2
SELECT ROUND(-1,43);#-1
SELECT ROUND(1.3447,2);#结果保留两个小数 1.34

ceil: 向上取整


SELECT CEIL(1.32); #2
SELECT CEIL(-1.23);#-1

floor: 向下取整

SELECT FLOOR(-9.99);#-10
SELECT FLOOR(2.76);# 2

 truncate: 截断

SELECT TRUNCATE(2.2345,1);#2.2 保留一个小数
SELECT TRUNCATE(2.2345,2);#2.23 保留两个小数

 mod: 取余

SELECT MOD(10,-3); #1
SELECT 10%3; #1

rand: 随机数
    

 1.3.日期函数:


    now: 当前系统日期+时间

SELECT NOW();#2023-08-17  08:43:42

curdate: 当前系统日期

SELECT CURDATE();#2023-08-17

 curtime: 当前系统时间

SELECT CURTIME();#09:13:06


    year:年
    month:月
    monthname
    day
    hour:小时
    minute:分钟
    second:秒

SELECT YEAR(NOW()) 年;#2023
SELECT YEAR('1998-1-1')年;#1998

SELECT YEAR(hiredate) 年 FROM employees;

SELECT MONTH(NOW()) 月;#8yue
SELECT MONTHNAME(NOW()) 月;#August


    str_to_date: 将字符转换成日期

SELECT STR_TO_DATE('1998-3-2','%Y-%c-%d')AS out_put;#1998-03-02

date_format: 将日期转换成字符

SELECT DATE_FORMAT(NOW(),'%Y年%m月%d日') AS out_put;# 2023年08月17日

1. 4.其他函数:


    version: 版本
    database: 当前库
    user: 当前连接用户
    passwd('字符'):返回该字符的密码形式
    md5('字符'):返回该字符的md5加密形式

    
1.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
    


    if 处理双分支
    case语句 处理多分支
        情况1:处理等值判断
        情况2:处理条件判断

2、分组函数

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

1、简单 的使用   语法

SELECT SUM(salary) FROM employees;
SELECT AVG(salary) FROM employees;
SELECT MAX(salary) FROM employees;
SELECT MIN(salary) FROM employees;
SELECT COUNT(salary) FROM employees;

SELECT SUM(salary) 和,AVG(salary) 平均,MAX(salary) 最高,MIN(salary) 最低,COUNT(salary) 个数
FROM employees;

2、参数支持那些类型

SELECT SUM(last_name),AVG(last_name) FROM employees;
SELECT SUM(hiredate),AVG(hiredate)FROM employees;

SELECT MAX(last_name),MIN(last_name) FROM employees;
 
SELECT MAX(hiredate),MIN(hiredate) FROM employees; 

SELECT COUNT(commission_pct) FROM employees;
SELECT COUNT(last_name) FROM employees;

3、是否忽略null值

SELECT SUM(commission_pct),AVG(commission_pct),SUM(commission_pct)/35,SUM(commission_pct)/107 FROM employees;

SELECT MAX(commission_pct),MIN(commission_pct)FROM employees;

SELECT COUNT(commission_pct)FROM employees;
SELECT commission_pct FROM employees;

4、和distinct(去重)搭配

SELECT SUM(DISTINCT salary),SUM(salary) FROM employees;

SELECT COUNT(DISTINCT salary),COUNT(salary) FROM employees;

5、count函数的详细介绍

SELECT COUNT(salary) FROM employees;
#相当
SELECT COUNT(*) FROM employees;
#与上方想当
SELECT COUNT(1) FROM employees;

特点:
1、sum、avg一般用于处理数值型
   max、min、count可以处理任何类型
   
2、以上分组函数都忽略null值

3、可以和distinct搭配实现去重的运算

4、count函数的单独性质
一般使用count(*)用作统计行数
    count(1):统计结果集的行数
count(字段):统计该字段非空值的个数

5、和分组函数一同查询的字段要求是group by后的字段

效率:
MYISAM存储引擎下,COUNT(*)的效率高
INNODB存储引擎下,COUNT(*)和COUNT(1)的效率差不多,比COUNT(字段)高一些

五、分组查询

语法:
	select 分组函数,列(要求出现在group by的后面)  5
	from 表     1
	【where 筛选条件】   2
	 group by 分组的列表   3
	【having 分组后的筛选】   4
	【order by 排序列表】  6
注意:
	查询列表必须特殊,要求是分组函数和group by后出现的字段 

特点:
    1、分组查询中的筛选条件分为两类
            关键字          数据源            位置                
    分组前筛选    where           原始表            group by子句在前面        
    分组后筛选    having           分组后的结果集        group by子句在后面        
     
    1.分组函数做条件肯定是放在having子句中
    2.能用分组前筛选的,就优先考虑使用分组前筛选

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

SELECT AVG(salary) FROM employees;

简单的分组查询

#案例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:查询每个工种有奖金的员工的最高工资>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

案例3:查询领导编号>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) len_name
FROM employees
GROUP BY LENGTH(last_name);

 #2.添加筛选条件
SELECT COUNT(*) c,LENGTH(last_name) len_name
FROM employees
GROUP BY  len_name
HAVING c>5;

六、连接查询

1.含义:又称多表查询,当查询的字段来自于多个表时,就会用到连接查询

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

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

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


    sql92标准:仅支持内连接
SQL92语法:
	SELECT 查询列表
	FROM 表名1 别名1 ,表名2 别名2 
	WHERE 连接条件 				
	AND 筛选条件				
	GROUP BY 分组列表			
	HAVING 分组后筛选条件		  
	ORDER BY 排序列表

1、等值连接

	select 查询列表
	from  表1 别名,表2 别名
	where 表1.key=表2.key
	【and 筛选条件】
	【group by 分组字段】
	【having 分组后的筛选】
	【order by 排序字段】

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

#案例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 查询列表
	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 排序字段】

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

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 别名 【连接类型】
	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 departments d
 JOIN  employees e
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%';

二)非等值连接

查询员工的工资级别
SELECT salary,grade_level
FROM employees e
 JOIN job_grades g
 ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`;
 
 
 #查询工资级别的个数>20的个数,并且按工资级别降序
 SELECT COUNT(*),grade_level
FROM employees e
 JOIN job_grades g
 ON e.`salary` BETWEEN g.`lowest_sal` AND g.`highest_sal`
 GROUP BY grade_level
 HAVING COUNT(*)>20
 ORDER BY grade_level DESC;

三)自连接

 #查询员工的名字、上级的名字
 SELECT e.last_name,m.last_name
 FROM employees e
 JOIN employees m
 ON e.`manager_id`= m.`employee_id`;
 
  #查询姓名中包含字符k的员工的名字、上级的名字
 SELECT e.last_name,m.last_name
 FROM employees e
 JOIN employees m
 ON e.`manager_id`= m.`employee_id`
 WHERE e.`last_name` LIKE '%k%';

二、外连接

 应用场景:用于查询一个表中有,另一个表没有的记录

特点:
 1、外连接的查询结果为主表中的所有记录
    如果从表中有和它匹配的,则显示匹配的值
    如果从表中没有和它匹配的,则显示null
    外连接查询结果=内连接结果+主表中有而从表没有的记录
 2、左外连接,left join左边的是主表
    右外连接,right join右边的是主表
 3、左外和右外交换两个表的顺序,可以实现同样的效果 
 4、全外连接=内连接的结果+表1中有但表2没有的+表2中有但表1没有的

引入:查询男朋友 不在男神表的的女神名

 SELECT * FROM beauty;
 SELECT * FROM boys;

左外连接

 SELECT b.*,bo.*
 FROM boys bo
 LEFT OUTER JOIN beauty b
 ON b.`boyfriend_id` = bo.`id`
 WHERE b.`id` IS 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;
 
 
 #右外
  SELECT d.*,e.employee_id
 FROM employees e
 RIGHT OUTER JOIN departments d
 ON d.`department_id` = e.`department_id`
 WHERE e.`employee_id` IS NULL;
 
 
 #全外
  USE girls;
 SELECT b.*,bo.*
 FROM beauty b
 FULL OUTER JOIN boys bo
 ON b.`boyfriend_id` = bo.id;

交叉连接

 SELECT b.*,bo.*
 FROM beauty b
 CROSS JOIN boys bo;

sql92和 sql99pk

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

 七、子查询

含义:
出现在其他语句中的select语句,称为子查询或内查询
外部的查询语句,称为主查询或外查询

分类:
按子查询出现的位置:
    select后面:
        仅仅支持标量子查询
    
    from后面:
        支持表子查询
    where或having后面:★
        标量子查询(单行) √
        列子查询  (多行) √
        
        行子查询
        
    exists后面(相关子查询)
        表子查询
按结果集的行列数不同:
    标量子查询(结果集只有一行一列)
    列子查询(结果集只有一列多行)
    行子查询(结果集有一行多列)
    表子查询(结果集一般为多行多列)

一、where或having后面

1、标量子查询(单行子查询)

案例1:谁的工资比 Abel 高?

#①查询Abel的工资
SELECT salary
FROM employees
WHERE last_name = 'Abel'

#②查询员工的信息,满足 salary>①结果
SELECT *
FROM employees
WHERE salary>(

	SELECT salary
	FROM employees
	WHERE last_name = 'Abel'

);

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

#①查询141号员工的job_id
SELECT job_id
FROM employees
WHERE employee_id = 141

#②查询143号员工的salary
SELECT salary
FROM employees
WHERE employee_id = 143

#③查询员工的姓名,job_id 和工资,要求job_id=①并且salary>②

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

);


2、列子查询(多行子查询)

案例1:返回location_id是1400或1700的部门中的所有员工姓名

#①查询location_id是1400或1700的部门编号
SELECT DISTINCT department_id
FROM departments
WHERE location_id IN(1400,1700)

#②查询员工姓名,要求部门号是①列表中的某一个

SELECT last_name
FROM employees
WHERE department_id  <>ALL(
	SELECT DISTINCT department_id
	FROM departments
	WHERE location_id IN(1400,1700)

);


3、行子查询(多列多行)

案例:查询员工编号最小并且工资最高的员工信息

SELECT * 
FROM employees
WHERE (employee_id,salary)=(
	SELECT MIN(employee_id),MAX(salary)
	FROM employees
);

#①查询最小的员工编号
SELECT MIN(employee_id)
FROM employees


#②查询最高工资
SELECT MAX(salary)
FROM employees


#③查询员工信息
SELECT *
FROM employees
WHERE employee_id=(
	SELECT MIN(employee_id)
	FROM employees

)AND salary=(
	SELECT MAX(salary)
	FROM employees

);

特点:
①子查询放在小括号内
②子查询一般放在条件的右侧
③标量子查询,一般搭配着单行操作符使用
> < >= <= = <>

列子查询,一般搭配着多行操作符使用
in、any/some、all

④子查询的执行优先于主查询执行,主查询的条件用到了子查询的结果

非法使用标量子查询

SELECT MIN(salary),department_id
FROM employees
GROUP BY department_id
HAVING MIN(salary)>(
	SELECT  salary
	FROM employees
	WHERE department_id = 250
);

二、select后面

仅仅支持标量子查询

案例:查询每个部门的员工个数

SELECT d.*,(
	SELECT COUNT(*)
	FROM employees e
	WHERE e.department_id = d.`department_id`
 ) 个数
 FROM departments d;

案例2:查询员工号=102的部门名

SELECT (
	SELECT department_name,e.department_id
	FROM departments d
	INNER JOIN employees e
	ON d.department_id=e.department_id
	WHERE e.employee_id=102
) 部门名;

三、from后面

将子查询结果充当一张表,要求必须起别名

案例:查询每个部门的平均工资的工资等级

#①查询每个部门的平均工资
SELECT AVG(salary),department_id
FROM employees
GROUP BY department_id


SELECT * FROM job_grades;


#②连接①的结果集和job_grades表,筛选条件平均工资 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_grades g
ON ag_dep.ag BETWEEN lowest_sal AND highest_sal;

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

语法:
exists(完整的查询语句)
结果:
1或0

案例1:查询有员工的部门名        

#in
SELECT department_name
FROM departments d
WHERE d.`department_id` IN(
	SELECT department_id
	FROM employees
)

#exists

SELECT department_name
FROM departments d
WHERE EXISTS(
	SELECT *
	FROM employees e
	WHERE d.`department_id`=e.`department_id`

);

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

八、分页查询

应用场景:当要显示的数据,一页显示不全,需要分页提交sql请求

语法:
	select 查询列表
	from 表
	【join type join 表2
	on 连接条件
	where 筛选条件
	group by 分组字段
	having 分组后的筛选
	order by 排序的字段】
	limit 【offset,】size;
	
	offset要显示条目的起始索引(起始索引从0开始)
	size 要显示的条目个数

特点:
    ①limit语句放在查询语句的最后
    ②公式
    要显示的页数 page,每页的条目数size
    
    select 查询列表
    from 表
    limit (page-1)*size,size;
    
    size=10
    page  
    1    0
    2      10
    3    20

案例1:查询前五条员工信息

SELECT * FROM  employees LIMIT 0,5;
SELECT * FROM  employees LIMIT 5;

案例2:查询第11条——第25条

SELECT * FROM  employees LIMIT 10,15;

案例3:有奖金的员工信息,并且工资较高的前10名显示出来

SELECT 
    * 
FROM
    employees 
WHERE commission_pct IS NOT NULL 
ORDER BY salary DESC 
LIMIT 10 ;

 

九、联合查询

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 FROM t_ca WHERE csex='男'
UNION ALL
SELECT t_id,tname FROM t_ua WHERE tGender='male';

 

TCL语言

Transaction Control Language 事务控制语言

一、事务

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


二、事务的特性:


ACID
原子性:一个事务不可再分割,要么都执行要么都不执行
一致性:一个事务执行会使数据从一个一致状态切换到另外一个一致状态
隔离性:一个事务的执行不受其他事务的干扰
持久性:一个事务一旦提交,则会永久的改变数据库的数据.

三、事务的创建


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

delete from 表 where id =1;

显式事务:事务具有明显的开启和结束的标记
前提:必须先设置自动提交功能为禁用

set autocommit=0;

步骤1:开启事务
set autocommit=0;
start transaction;可选的
步骤2:编写事务中的sql语句(select insert update delete)
语句1;
语句2;
...

步骤3:结束事务
commit;提交事务
rollback;回滚事务

savepoint 节点名;设置保存点

1.演示事务的使用步骤

开启事务
SET autocommit=0;
START TRANSACTION;

编写一组事务的语句
UPDATE account SET balance = 1000 WHERE username='张无忌';
UPDATE account SET balance = 1000 WHERE username='赵敏';

结束事务
ROLLBACK;
#commit;

SELECT * FROM account;

2.演示事务对于delete和truncate的处理的区别

SET autocommit=0;
START TRANSACTION;

DELETE FROM account;
ROLLBACK;
 

3.演示savepoint 的使用

SET autocommit=0;
START TRANSACTION;
DELETE FROM account WHERE id=25;
SAVEPOINT a;#设置保存点
DELETE FROM account WHERE id=28;
ROLLBACK TO a;#回滚到保存点

SELECT * FROM account;

四、事务的隔离级别:


          脏读        不可重复读    幻读
read uncommitted:√        √        √
read committed:  ×        √        √
repeatable read: ×        ×        √
serializable      ×             ×          ×

mysql中默认 第三个隔离级别 repeatable read
oracle中默认第二个隔离级别 read committed
查看隔离级别
select @@tx_isolation;
设置隔离级别
set session|global transaction isolation level 隔离级别;

开启事务的语句;
update 表 set 张三丰的余额=500 where name='张三丰'

update 表 set 郭襄的余额=1500 where name='郭襄' 
结束事务的语句;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值