2.DQL数据查询语言

DQL数据查询语言

一. SQL概述

1. 什么是SQL

​ **SQL(Structured Query Language)**是“结构化查询语言”,它是对关系型数据库的操作语言。它可以应用到所有关系型数据库中,例如:MySQL、Oracle、SQL Server等。

​ 虽然SQL可以用在所有关系型数据库中,但很多数据库都有自己的一套语法。例如MySQL中的LIMIT分页语句就是MySQL独有的方言,其它数据库都不支持。当然,Oracle或SQL Server也都有自己的语法。

2. SQL语法要求

1). SQL语句可以单行或多行书写,以分号结尾;

2). 可以用空格和缩进来来增强语句的可读性;

3). 关键字不区别大小写,建议使用大写;

3. SQL分类

1). **DQL(Data Query Language):数据查询语言,用来查询记录(数据) select **

2). DML(Data Manipulation Language):数据操作语言,用来定义数据库记录(数据) insert / update / delete

3). DDL(Data Definition Language):数据定义语言,用来定义数据库对象:库、表、列等 create / drop / alter/desc

4). DCL(Data Control Language):数据控制语言,用来定义访问权限和安全级别

5). TCL(Transaction Control Language) :事务控制语言 事务提交commit,事务回滚rollback,保存点savepoint

二. DQL数据查询语言

2.1 概念

DQL(Data Query Language):数据查询语言,用来查询记录(数据) 执行**select操作**

DQL就是数据查询语言,数据库执行DQL语句不会对数据进行改变,而是让数据库发送结果集给客户端。

2.2 语法

SELECT 

selection_list  /*要查询的列名称*/

FROM 

table_list   /*要查询的表名称*/

WHERE 

condition /*行条件*/

GROUP BY 

grouping_columns /*对结果分组*/

HAVING 

condition /*分组后的行条件*/

ORDER BY

sorting_columns /*对结果排序*/

LIMIT 

offset_start, row_count /*结果限定(分页)*/

2.3 准备工作 - 创建表结构

执行初始化脚本 employee.sql,创建并插入以下数据。

运行sql文件的方式:

  • 方式1:命令行

    use testdql;
    source employee.sql文件的绝对路径
    
  • 方式2:navicat中运行sql文件

员工表:employees

字段名称字段类型说明
employee_idint(6)员工编号 ,非空,主键,自增长
first_namevarchar(20)员工姓
last_namevarchar(25)员工名
emailvarchar(25)邮箱
phone_numbervarchar(20)电话
job_idvarchar(10) 字符串类型工种编号,外键关联工种表中的主键
salarydouble(10,2) 浮点类型月薪
commission_pctdouble(4,2) 有效位数4位,小数点2位奖金率
manager_idint(6)领导编号,来源于本表中的employee_id
department_idint(4)部门编号,外键关联部门表中的主键
hiredatedatetime 日期时间类型入职时间

部门表:departments

字段名称字段类型说明
department_idint(4) 整型部门编号,非空,主键,自增长
department_namevarchar(3) 字符串类型部门名称
manager_idint(6)部门领导编号
location_idint(4)位置编号,外键关联区域表中的主键

工种表:jobs

字段名称字段类型说明
job_idvarchar(10) 字符串类型工种编号,非空,主键
job_titlevarchar(35)工种名称
min_salaryint(6) 整型最低工资
max_salaryint(6)最高工资

位置表:locations

字段名称字段类型说明
location_idint(11) 整型位置编号,非空,主键,自增长
street_addressvarchar(40) 字符串类型街道地址
postal_codevarchar(12)邮编
cityvarchar(30)城市
state_provincevarchar(25)州/省
country_idvarchar(2)国家编号

三. 基础查询

3.1 语法

select 查询列表 from 表名;

其中select后面跟的查询列表,可以有多个部分组成,中间用逗号隔开,例如:
select 字段1,字段2,表达式 from;	

3.2 执行顺序

from子句
select子句

3.3 查询列表

字段、表达式、常量、函数等

3.4 案例

-- 一、查询常量

-- 二、查询表达式

-- 三、查询单个字段

-- 四、查询多个字段

-- 五、查询所有字段
    
-- 六、查询函数(调用函数,获取返回值)

-- 七、给查询字段起别名
#方式一:使用as关键字
#方式二:使用空格

-- 八、+的作用
-- 1.两个操作数都是数值型,执行加法操作
-- 2.其中一个操作数为字符型,一个操作数为数值,则将字符型数据强制转换成数值型,如果无法转换,则直接当做0处理
-- 3.其中一个操作数为null,结果为null

-- 九、distinct的使用,去除重复记录
#需求:查询员工涉及到的部门编号

-- 十、查看表的结构
-- 一、查询常量
SELECT 123;

-- 二、查询表达式
SELECT 1+2;

-- 三、查询单个字段
SELECT employee_id from employees;

-- 四、查询多个字段
SELECT employee_id,first_name from employees;

-- 五、查询所有字段
SELECT * from employees;
    
-- 六、查询函数(调用函数,获取返回值)
-- 拼接字符串  concat()
SELECT CONCAT(first_name,'$',last_name) from employees;

-- 七、给查询字段起别名
#方式一:使用as关键字
SELECT CONCAT(first_name,'$',last_name) as 姓名 from employees;
#方式二:使用空格
SELECT CONCAT(first_name,'$',last_name) 'name' from employees;

-- 八、+的作用
-- 1.两个操作数都是数值型,执行加法操作
select 1+2; -- 3
-- 2.其中一个操作数为字符型,一个操作数为数值,则将字符型数据强制转换成数值型,如果无法转换,则直接当做0处理
SELECT '1'+2;  -- 3
SELECT '1a'+2;  -- 3 从第一个数字开始转换 直到非数字结束转换
SELECT 'a1'+2;  -- 2 无法转换的直接当作0处理
-- 3.其中一个操作数为null,结果为null
SELECT NULL+NULL; -- NULL  任何数据和null的运算结果都是null

SELECT first_name,commission_pct,salary,salary*commission_pct '奖学金' FROM employees;
-- 查询所有员工的奖金额  如果没有奖金则显示0  IFNULL(字段,如果字段为null则显示的内容)
SELECT first_name,commission_pct,salary,IFNULL(commission_pct,0)*salary '奖金额' from employees;

-- 九、distinct的使用,去除重复记录
#需求:查询员工涉及到的部门编号
SELECT DISTINCT department_id from employees;

-- 十、查看表的结构
desc employees;

四. 条件查询

4.1 语法

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

4.2 执行顺序

from子句
where子句
select子句

4.3 案例

-- 一、按关系表达式筛选  关系运算符:>  <  >=  <=  =  <>    补充:也可以使用!=,但不建议
#案例1:查询部门编号不是100的员工信息
#案例2:查询工资<15000的姓名、工资

-- 二、按逻辑表达式筛选 逻辑运算符:and  or   not   补充:也可以使用&&  ||   !  ,但不建议
#案例1:查询部门编号不是 50-100之间员工姓名、部门编号、邮箱
#案例2:查询奖金率>0.03 或者 员工编号在60-110之间的员工信息

-- 三、模糊查询 like/not like 
#案例1:查询姓名中包含字符a的员工信息
#案例2:查询姓名中包含最后一个字符为e的员工信息
#案例3:查询姓名中包含第一个字符为e的员工信息
#案例4:查询姓名中包含第三个字符为x的员工信息
#案例5:查询姓名中包含第二个字符为_的员工信息

-- 四、查询某字段的值是否属于指定的列表之内  in/not in
#案例1:查询部门编号是30/50/90的员工名、部门编号
#案例2:查询工种编号不是SH_CLERK或IT_PROG的员工信息

-- 五、判断某个字段的值是否介于指定的区间范围  between and/not between and
#案例1:查询部门编号是30-90之间的部门编号、员工姓名
#案例2:查询年薪不是100000-200000之间的员工姓名、工资、年薪

-- 六、查询是null字段  is null , 查询不是null字段  is not null
#案例1:查询没有奖金的员工信息
#案例2:查询有奖金的员工信息
-- 一、按关系表达式筛选  关系运算符:>  <  >=  <=  =  <>    补充:也可以使用!=,但不建议
#案例1:查询部门编号不是100的员工信息
SELECT *
FROM employees
WHERE department_id<>100;
#案例2:查询工资<15000的姓名、工资
SELECT first_name '姓名',salary '工资'
FROM employees
WHERE salary<15000;
-- 二、按逻辑表达式筛选 逻辑运算符:and  or   not   补充:也可以使用&&  ||   !  ,但不建议
#案例1:查询部门编号不是 50-100之间员工姓名、部门编号、邮箱
SELECT first_name '用户名',department_id '部门编号',email '邮箱'
FROM employees
where department_id>100 or department_id<50;

SELECT first_name '用户名',department_id '部门编号',email '邮箱'
FROM employees
where department_id not BETWEEN 50 and 100;
#案例2:查询奖金率>0.03 或者 员工编号在60-110之间的员工信息
SELECT *
FROM employees
where commission_pct>0.03 OR department_id BETWEEN 60 AND 110;


-- 三、模糊查询 like/not like 
#案例1:查询姓名中包含字符a的员工信息
SELECT *
from employees
WHERE first_name LIKE('%a%');

#案例2:查询姓名中包含最后一个字符为e的员工信息
SELECT *
FROM employees
WHERE first_name LIKE('%a');

#案例3:查询姓名中包含第一个字符为e的员工信息
SELECT *
FROM employees
WHERE first_name LIKE('a%');

#案例4:查询姓名中包含第三个字符为x的员工信息
SELECT *
FROM employees
WHERE first_name LIKE('__x%');

#案例5:查询姓名中包含第二个字符为_的员工信息  字段为last_name
SELECT *
FROM employees
WHERE last_name LIKE '_\_%';  -- \_转义字符 字面值下划线

-- ESCAPE 指定哪一个字符充当转义字符 $
SELECT last_name
FROM employees
WHERE last_name LIKE '_$_%' ESCAPE '$';

-- 四、查询某字段的值是否属于指定的列表之内  in/not in
#案例1:查询部门编号是30/50/90的员工名、部门编号
SELECT first_name ,department_id
FROM employees
WHERE department_id in (30,50,90);

#案例2:查询工种编号不是SH_CLERK或IT_PROG的员工信息
SELECT job_id
from employees
WHERE job_id NOT IN('SH_CLERK','IT_PROG');

-- 五、判断某个字段的值是否介于指定的区间范围  between and/not between and
#案例1:查询部门编号是30-90之间的部门编号、员工姓名
SELECT department_id,first_name
from employees
WHERE department_id BETWEEN 30 AND 90;

#案例2:查询年薪不是100000-200000之间的员工姓名、工资、年薪
SELECT first_name,salary,salary*12 '年薪'
FROM employees
WHERE salary*12 NOT BETWEEN 100000 AND 200000;

-- 六、查询是null字段  is null , 查询不是null字段  is not null
#案例1:查询没有奖金的员工信息
select *
from employees
where commission_pct is NULL;
#案例2:查询有奖金的员工信息
select *
from employees
where commission_pct is NOT NULL;

-- 七、SQL注入问题
select * from employees where first_name='John' AND email='JSEO';
-- 可以进行破解  ''字符串拼接 or 1=1  为true -- 注解不执行
SELECT * from employees where first_name= '' or 1=1 -- ' AND email='JSEO';

4.4 特殊用法 之 IFNULL函数

因为salary和commission_pct两列的类型都是数值类型,所以可以做计算。如果salary或commission_pct中有一个字段不是数值类型,那么会出错。

​ 其中commission_pct列有很多记录的值为NULL,因为任何东西与NULL相加结果还是NULL,所以结算结果可能会出现NULL。

需求:下面使用函数IFNULL() 把NULL转换成数值0:

#ifnull(表达式1,表达式2)
/*
表达式1:可能为null的字段或表达式
表达式2:如果表达式1为null,则最终结果显示的值

功能:如果表达式1为null,则显示表达式2,否则显示表达式1
*/
SELECT commission_pct,IFNULL(commission_pct,0) FROM employees;

五. 排序查询 order by

5.1 语法

select   查询列表  from 表名  where 筛选条件  order by 排序列表

5.2 执行顺序

from子句
where子句
select子句
order by 子句

5.3 用法

1、排序列表可以是单个字段、多个字段、表达式、函数、列数、以及以上的组合

2、升序 ,通过 asc ,默认行为
降序 ,通过 desc

5.4 案例

-- 一、按单个字段排序
#案例1:将员工编号>120的员工信息进行工资的升序
#案例2:将员工编号>120的员工信息进行工资的降序

-- 二、按表达式排序
#案例:对有奖金的员工,按年薪降序

-- 三、按别名排序
#案例:对有奖金的员工,按年薪降序

-- 四、按函数的结果排序
#案例:按姓名的字数长度进行升序

-- 五、按多个字段排序
#案例:查询员工的姓名、工资、部门编号,先按工资升序,再按部门编号降序

-- 六、按列数排序(不做要求)
#案例:按第二列排序
-- 一、按单个字段排序
#案例1:将员工编号>120的员工信息进行工资的升序
SELECT employee_id,salary
FROM employees
WHERE employee_id>120
ORDER BY salary;

#案例2:将员工编号>120的员工信息进行工资的降序
SELECT employee_id,salary
FROM employees
WHERE employee_id>120
ORDER BY salary DESC;

-- 二、按表达式排序
#案例:对有奖金的员工,按年薪降序
SELECT *
from employees
where commission_pct IS NOT NULL
ORDER BY salary DESC;


-- 三、按别名排序
#案例:对有奖金的员工,按年薪降序  
SELECT first_name,salary*12 '年薪'
FROM employees
WHERE commission_pct is not null  
ORDER BY '年薪' DESC;  -- order_by  执行顺序在 select之后  可以使用别名  '年薪'作为常量不进行排序

-- 四、按函数的结果排序
#案例:按姓名的字数长度进行升序  LENGTH(str)字节长度  CHAR_LENGTH(str)字符长度
SELECT first_name,LENGTH(first_name) as a
from employees
ORDER BY a asc;  -- 识别的不是常量 而是字段别名

select first_name,CHAR_LENGTH(first_name) '字符长度'
from employees
order by CHAR_LENGTH(first_name) desc;

-- 五、按多个字段排序
#案例:查询员工的姓名、工资、部门编号,先按工资升序,再按部门编号降序
SELECT first_name,salary,department_id
FROM employees
ORDER BY salary asc, department_id DESC;


-- 六、按列数排序(不做要求)
#案例:按第二列排序
SELECT *
from employees
ORDER BY 1;


六. 常见函数

​ 函数:类似于java中学过的“方法”,为了解决某个问题,将编写的一系列的命令集合封装在一起,对外仅仅暴露函数名,供外部调用。

6.1 字符串函数

1). 常用函数

字符串函数名函数说明
CONCAT(S1,S2,…,Sn)连接S1,S2,…,Sn为一个字符串
CONCAT_WS(s, S1,S2,…,Sn)同CONCAT(s1,s2,…)函数,但是每个字符串之间要加上s
CHAR_LENGTH(s)返回字符串s的字符数
LENGTH(s)返回字符串s的字节数,和字符集有关
INSERT(str, index , len, instr)将字符串str从第index位置开始,len个字符长的子串替换为字符串instr
UPPER(s) 或 UCASE(s)将字符串s的所有字母转成大写字母
LOWER(s) 或LCASE(s)将字符串s的所有字母转成小写字母
LEFT(s,n)返回字符串s最左边的n个字符
RIGHT(s,n)返回字符串s最右边的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(【BOTH 】s1 FROM s)去掉字符串s开始与结尾的s1
TRIM(【LEADING】s1 FROM s)去掉字符串s开始处的s1
TRIM(【TRAILING】s1 FROM s)去掉字符串s结尾处的s1
REPEAT(str, n)返回str重复n次的结果
REPLACE(str, a, b)用字符串b替换字符串str中所有出现的字符串a
STRCMP(s1,s2)比较字符串s1,s2
SUBSTRING(s,index,len)返回从字符串s的index位置其len个字符

2). 案例

#一、字符函数
-- 1、CONCAT 拼接字符

-- 2、LENGTH 获取字节长度

-- 3、CHAR_LENGTH 获取字符个数

-- 4、INSERT 插入新字符串

-- 5、SUBSTRING 截取子串  注意:起始索引从1开始
-- SUBSTRING(str,pos) 第一个参数是:截取的字符串  第二个参数是起始位置,从1开始
-- SUBSTRING(str,pos,len) 第一个参数是:截取的字符串  第二个参数是起始位置,从1开始  第三个参数是截取的长度
-- SUBSTRING(str,pos)第二个参数是负数,从后往前截取几位
-- 类似于 SUBSTR(str FROM pos) 

-- 6、TRIM去前后指定的字符,默认是去空格
-- 用法:TRIM([remstr FROM] str) 默认去除左右空格
-- 用法:LTRIM(str) 默认去除左边空格
-- 用法:RTRIM(str) 默认去除右边空格
-- 用法:TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str)
-- 第一个参数:BOTH两边移除,LEADING左边移除,TRAILING右边移除  第二个参数:remstr移除的字符串 第三个参数:FROM关键字  第四个参数:操作的字符串

-- 7、LPAD/RPAD  左填充/右填充
-- LPAD(字符串,填充的长度,填充的内容) 左填充
-- RPAD(字符串,填充的长度,填充的内容) 右填充

-- 8、UPPER/LOWER  变大写/变小写
#案例:查询员工表的姓名,要求格式:姓首字符大写,其他字符小写,名所有字符大写,且姓和名之间用_分割,最后起别名“OUTPUT”

-- 9、STRCMP 比较两个字符大小

-- 10、LEFT/RIGHT  截取子串

-- 11、REPEAT(str,count)  第一个参数:操作的字符串   第二个参数:重复的次数

-- 12、REPLACE(str,from_str,to_str) 第一个参数:操作的字符串  第二个参数:将要替换的字符串  第三个参数:替换成字符串

-- 13、INSTR获取字符第一次出现的索引
#一、字符函数
-- 1、CONCAT 拼接字符
SELECT CONCAT(first_name,'$',last_name)
FROM employees

-- 2、LENGTH 获取字节长度  utf-8 字符集一个中文占3个字节
SELECT '你好' , LENGTH('你好') '字节个数';

-- 3、CHAR_LENGTH 获取字符个数
SELECT '你好' , CHAR_LENGTH('你好') '字符个数';  -- 2

-- 4、INSERT 插入新字符串 
SELECT INSERT(first_name,1,0,'aaa') from employees;  -- 在头部插入
SELECT INSERT(first_name,1,2,'XX') from employees;  -- 在替换

-- 5、SUBSTRING 截取子串  注意:起始索引从1开始
-- SUBSTRING(str,pos) 第一个参数是:截取的字符串  第二个参数是起始位置,从1开始
SELECT SUBSTRING(first_name,2) from employees;

-- SUBSTRING(str,pos,len) 第一个参数是:截取的字符串  第二个参数是起始位置,从1开始  第三个参数是截取的长度
SELECT substring(first_name,1,2) from employees;

-- SUBSTRING(str,pos)第二个参数是负数,从后往前截取几位
SELECT SUBSTRING(first_name,-2) FROM employees;

-- 类似于 SUBSTR(str FROM pos) 

-- 6、TRIM去前后指定的字符,默认是去空格

-- 用法:TRIM([remstr FROM] str) 默认去除左右空格
SELECT LENGTH('   abc   '),LENGTH(TRIM('   abc   ')),TRIM('   abc   ');

-- 用法:LTRIM(str) 默认去除左边空格
SELECT LENGTH('   abc   '),LENGTH(LTRIM('   abc   ')),LTRIM('   abc   ');

-- 用法:RTRIM(str) 默认去除右边空格
SELECT LENGTH('   abc   '),LENGTH(RTRIM('   abc   ')),RTRIM('   abc   ');
-- 用法:TRIM([{BOTH | LEADING | TRAILING} [remstr] FROM] str)
-- 第一个参数:BOTH两边移除,LEADING左边移除,TRAILING右边移除  第二个参数:remstr移除的字符串 第三个参数:FROM关键字  第四个参数:操作的字符串
SELECT LENGTH('###abc###'),LENGTH(TRIM(BOTH '###' FROM '###abc###')),TRIM(BOTH '###' FROM '###abc###');
SELECT LENGTH('###abc###'),LENGTH(TRIM(LEADING '###' FROM '###abc###')),TRIM(LEADING '###' FROM '###abc###');
SELECT LENGTH('###abc###'),LENGTH(TRIM(TRAILING '###' FROM '###abc###')),TRIM(TRAILING '###' FROM '###abc###');
-- 7、LPAD/RPAD  左填充/右填充
-- LPAD(字符串,填充的长度,填充的内容) 左填充
SELECT LPAD('abc',10,'@'), LENGTH(LPAD('abc',10,'@'));
-- RPAD(字符串,填充的长度,填充的内容) 右填充
SELECT RPAD('abc',10,'@'),LENGTH(RPAD('abc',10,'@'));

-- 8、UPPER/LOWER  变大写/变小写
#案例:查询员工表的姓名,要求格式:姓首字符大写,其他字符小写,名所有字符大写,且姓和名之间用_分割,最后起别名“OUTPUT”
SELECT CONCAT(upper(SUBSTRING(first_name,1,1)),LOWER(SUBSTRING(first_name,2)),'_',UPPER(last_name)) 'output' 
FROM employees

-- 9、STRCMP 比较两个字符大小
select STRCMP('a','b');   -- 小于  -1
select STRCMP('c','b');   -- 大于  1

-- 10、LEFT/RIGHT  截取子串
select LEFT(first_name,2) FROM employees;  -- 从左开始截取
select RIGHT(first_name,2) FROM employees;  -- 从右开始截取


-- 11、REPEAT(str,count)  第一个参数:操作的字符串   第二个参数:重复的次数
SELECT repeat('abc',3);

-- 12、REPLACE(str,from_str,to_str) 第一个参数:操作的字符串  第二个参数:将要替换的字符串  第三个参数:替换成字符串
SELECT REPLACE(first_name,'a','#') from employees;
-- 13、INSTR(str,substr)获取字符第一次出现的索引
SELECT INSTR('abca','ab');   -- 1
SELECT INSTR('abca','abbb');   -- 0  没有查找到返回0 

6.2 数学函数

1). 常用函数

数学函数名函数说明
ABS(x)返回x的绝对值
CEIL(x)返回大于x的最小整数值
FLOOR(x)返回大于x的最大整数值
MOD(x,y)返回x/y的模
RAND(x)返回0~1的随机值
ROUND(x,y)返回参数x的四舍五入的有y位的小数的值
TRUNCATE(x,y)返回数字x截断为y位小数的结果
SQRT(x)返回x的平方根
POW(x,y)返回x的y次方

2). 案例

#二、数学函数
-- 1、ABS 绝对值

-- 2、CEIL 向上取整  返回>=该参数的最小整数

-- 3、FLOOR 向下取整,返回<=该参数的最大整数

-- 4、ROUND 四舍五入

-- 5、TRUNCATE 截断

-- 6、MOD 取余

-- 7、RAND() 返回0~1的随机值

6.3 日期时间函数

1). 常用函数

日期时间函数函数说明
CURDATE() 或 CURRENT_DATE()返回当前日期
CURTIME() 或 CURRENT_TIME()返回当前时间
NOW()返回当前系统日期时间
SYSDATE()
CURRENT_TIMESTAMP()
LOCALTIME()
LOCALTIMESTAMP()
YEAR(date)返回指定时间的年
MONTH(date)返回指定时间的月
DAY(date)返回指定时间的日
HOUR(time)返回指定时间的小时
MINUTE(time)返回指定时间的分钟
SECOND(time)返回指定时间的秒
WEEK(date)返回一年中的第几周
WEEKOFYEAR(date)
DAYOFWEEK()返回当前是周几,注意:周日是1,周一是2,。。。周六是7
WEEKDAY(date)返回指定的时间是周几,注意,周1是0,周2是1,。。。周日是6
DAYNAME(date)返回指定的时间是星期几:MONDAY,TUESDAY…SUNDAY
MONTHNAME(date)返回指定的时间的月份:January,。。。。。
DATEDIFF(date1,date2)返回date1 - date2的日期间隔
TIMEDIFF(time1, time2)返回time1 - time2的时间间隔
DATE_ADD(datetime, INTERVALE expr , type)返回与给定日期时间相差INTERVAL时间段的日期时间
DATE_FORMAT(datetime ,fmt)按照字符串fmt格式化日期datetime值
STR_TO_DATE(str, fmt)按照字符串fmt对str进行解析,解析为一个日期

2). 案例

#三、日期函数
-- 1、NOW/SYSDATE  系统当前时间
-- 获取年的部分
-- 获取月的部分
-- 获取日的部分
-- 获取时的部分
-- 获取分的部分
-- 获取秒的部分
-- 获取是今年的第几周
-- 获取星期域


-- 2、CURDATE  系统当前日期

-- 3、CURTIME  系统当前时间

-- 4、系统当前时间戳

-- 5、DATEDIFF(date1,date2)  返回date1 - date2的日期间隔
-- TIMEDIFF(time1, time2)返回time1 - time2的时间间隔

-- 6、DATE_FORMAT(datetime ,fmt)  按照字符串fmt格式化日期datetime值
#案例:查看100号员工入职日期

-- 7、STR_TO_DATE 按指定格式解析字符串为日期类型
#案例:查看1998年6月以前入职的员工信息

-- 8、DATE_ADD(datetime, INTERVAL  expr  type)  返回与给定日期时间相差INTERVAL时间段的日期时间
/*
	使用 DATE_ADD(NOW(),INTERVAL 1 MONTH) 这个函数来进行修改时间
	第一个参数是要修改的时间;
	第二个参数固定写法;
	第三个参数的修改的值 : 如果正数就是加,负数就是减;
	第四个参数可填YEAR,MONTH,DAY,HOUR,MINUTE,SECOND;
*/

(1)DATE_ADD(datetime,INTERVAL expr type) 返回与给定日期时间相差INTERVAL时间段的日期时间

SELECT DATE_ADD(NOW(), INTERVAL 1 YEAR);   

SELECT DATE_ADD(NOW(), INTERVAL -1 YEAR);  #可以是负数

SELECT DATE_ADD(NOW(), INTERVAL '1_1' YEAR_MONTH);  #需要单引号
表达式类型
YEAR以年为单位追加
MONTH
DAY
HOUR
MINUTE
SECOND
YEAR_MONTH以年和月为单位追加
DAY_HOUR
DAY_MINUTE
DAY_SECOND
HOUR_MINUTE
HOUR_SECOND
MINUTE_SECOND

(2)DATE_FORMAT(datetime ,fmt) 和 STR_TO_DATE(str, fmt)

格式符说明格式符说明
%Y4位数字表示年份%y表示两位数字表示年份
%M月名表示月份(January,…)%m两位数字表示月份(01,02,03。。。)
%b缩写的月名(Jan.,Feb.,…)%c数字表示月份(1,2,3,…)
%D英文后缀表示月中的天数(1st,2nd,3rd,…)%d两位数字表示月中的天数(01,02…)
%e数字形式表示月中的天数(1,2,3,4,5…)
%H两位数字表示小数,24小时制(01,02…)%h和%I两位数字表示小时,12小时制(01,02…)
%k数字形式的小时,24小时制(1,2,3)%l数字形式表示小时,12小时制(1,2,3,4…)
%i两位数字表示分钟(00,01,02)%S和%s两位数字表示秒(00,01,02…)
%W一周中的星期名称(Sunday…)%a一周中的星期缩写(Sun.,Mon.,Tues.,…)
%w以数字表示周中的天数(0=Sunday,1=Monday…)
%j以3位数字表示年中的天数(001,002…)%U以数字表示年中的第几周,(1,2,3。。)其中Sunday为周中第一天
%u以数字表示年中的第几周,(1,2,3。。)其中Monday为周中第一天
%T24小时制%r12小时制
%pAM或PM%%表示%

6.4 流程控制函数

1). 常用函数

流程控制函数函数说明
IF(value,t ,f)如果value是真,返回t,否则返回f
IFNULL(value1, value2)如果value1不为空,返回value1,否则返回value2
CASE WHEN 条件1 THEN result1 WHEN 条件2 THEN result2…[ELSE resultn] END相当于Java的if…else if…
CASE expr WHEN 常量值1 THEN 值1 WHEN 常量值1 THEN 值1…[ELSE 值n] END相当于Java的switch
#例如
SELECT oid,`status`, 
CASE `status` 
WHEN 1 THEN '未付款'
WHEN 2 THEN '已付款'
WHEN 3 THEN '已发货'
WHEN 4 THEN '确认收货'
ELSE '无效订单'
END
FROM t_order;

2). 案例

#四、流程控制函数
-- 1.1、IF函数
-- 1.2、IFNULL函数
#需求:如果有奖金,则显示最终奖金,如果没有,则显示0

-- 2、CASE函数
/*
   情况1 :类似于switch语句,可以实现等值判断
   CASE 表达式
   WHEN 值1 THEN 结果1
   WHEN 值2 THEN 结果2
   ...
   ELSE 结果n
   END
*/
#案例:部门编号是30,工资显示为2倍;部门编号是50,工资显示为3倍;部门编号是60,工资显示为4倍;否则不变;
#显示部门编号,新工资,旧工资

/*
   情况2:类似于多重IF语句,实现区间判断
   CASE 
   WHEN 条件1 THEN 结果1
   WHEN 条件2 THEN 结果2
   ...
   ELSE 结果n
   END
*/
#案例:如果工资>20000,显示级别A;工资>15000,显示级别B;工资>10000,显示级别C;否则,显示D

6.5 分组(聚合)函数

​ 分组函数往往用于实现将一组数据进行统计计算,最终得到一个值,又称为聚合函数或统计函数,聚合函数是用来做纵向运算的函数。

1). 常用函数

COUNT():统计指定列不为NULL的记录行数;

MAX():计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;

MIN():计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;

SUM():计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0;

AVG():计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0;

2). 案例

#五、分组(聚合)函数
-- 案例:查询员工信息表中,所有员工的工资和、工资平均值、最低工资、最高工资、有工资的个数

-- count() 函数 直接去掉null值
#添加筛选条件
-- 案例1:查询emp表中记录数
-- 案例2:查询emp表中有佣金的人数
-- 案例3:查询emp表中月薪大于2500的人数
-- 案例4:查询有领导的人数
#其它用途
-- 案例5:统计结果集的行数,推荐使用count(*)。需求:查询员工表中30号部门的人数
-- 案例6:搭配distinct实现去重的统计。需求:查询有员工的部门个数

-- SUM() 求和函数
-- 案例7:查询所有员工月薪和

-- AVG() 平均值函数
-- 案例8:统计所有员工平均工资

-- MAX() 和 MIN()  最大值和最小值函数
-- 案例9:查询最高工资和最低工资

七. 分组查询

当需要分组查询时需要使用GROUP BY子句,例如查询每个部门的平均工资,这说明要使用部门来分组。

7.1 语法

select 查询列表

from 表名

where 筛选条件

group by 分组列表

having 分组后筛选

order by 排序列表;

7.2 执行顺序

from  子句

where 子句

group by 子句

having 子句

select 子句

order by 子句

7.3 用法

查询列表往往是,分组函数和被分组的字段

分组查询中的筛选分为两类:

筛选的基表使用的关键词位置
分组前筛选原始表wheregroup by的前面
分组后筛选分组后的结果集havinggroup by的后面

顺序:where——group by ——having

总结:1.分组函数做条件只可能放在having后面

​ 2.在select列表中所有未包含在分组函数中的列都应该包含在 group by子句中。 ==>查询列表往往是,分组函数和被分组的字段

7.4 案例

-- 1)简单的分组
#案例1:查询每个工种的员工平均工资
#案例2:查询每个领导的手下人数

-- 2)可以实现分组前的筛选
#案例1:查询邮箱中包含a字符的每个部门的最高工资
#案例2:查询每个领导手下有奖金的员工的平均工资

-- 3)可以实现分组后的筛选
#案例1:查询哪个部门的员工个数>5
#案例2:每个工种有奖金的员工的最高工资>12000的工种编号和最高工资
#案例3:领导编号>102的每个领导手下的最低工资大于5000的最低工资

-- 4)可以实现排序
#案例:查询没有奖金的员工的最高工资>6000的工种编号和最高工资,按最高工资升序

-- 5)按多个字段分组
#案例:查询每个工种每个部门的最低工资,并按最低工资降序。提示:工种和部门都一样,才是一组

八. 连接查询

8.1 准备工作 - 创建表结构

执行初始化脚本 person.sql,创建并插入以下数据。

女神表:girl

字段名称字段类型说明
idint(11)女生编号 ,主键,非空,自增长
namevarchar(50)姓名,非空
sexchar(1)性别,默认女
borndatedatetime生日
phonevarchar(11)手机号,非空
photoblob头像
boyfriend_idint(11)男朋友的编号,外键关联boy表中的主键

男神表:boy

字段名称字段类型说明
idint(11)男生编号 ,主键,非空,自增长
namevarchar(20)姓名

8.2 概念

连接查询又称多表查询,当查询语句涉及到的字段来自于多个表时,就会用到连接查询。

直接多表查询,会出现问题: 笛卡尔乘积现象,记录数是 表1 有m行,表2有n行,结果=m*n行

#查看新建的表数据
select count(*) from girl; -- 12
select count(*) from boy;  -- 6

#出现笛卡尔乘积现象 数据冗余
select girl.name '女' , boy.name '男' from girl , boy;  -- 72

发生原因:没有有效的连接条件,所有表中的所有行互相连接

如何避免:为了避免笛卡尔集, 可以在 WHERE 加入有效的连接条件

#解决方案:添加有效的连接条件
select girl.name '女' , boy.name '男' from girl , boy where girl.boyfriend_id = boy.id;

分析:

那么多表查询产生这样的结果并不是我们想要的,那么怎么去除重复的,不想要的记录呢,当然是通过条件过滤。通常要查询的多个表之间都存在关联关系,那么就通过关联关系去除笛卡尔积。

8.3 分类

按年代分类:

1). sql92标准:仅仅支持内连接. 内连接: 等值连接 非等值连接 自连接

2). sql99标准【推荐】:支持内连接 + 外连接(左外和右外)+ 交叉连接

按功能分类:

内连接: 等值连接 非等值连接 自连接

外连接: 左外连接 右外连接 全外连接(不支持)

交叉连接:笛卡尔积

自然连接

8.4 SQL92标准 内连接

1). 语法

select 查询列表

from1 别名 ,2 别名

where 连接条件 and 筛选条件

group by 分组列表

having 分组后筛选

order by 排序列表

2). 执行顺序

from子句

where子句

and子句

group by子句

having子句

select子句

order by子句

3). 等值连接

用法

1)多表等值连接的结果为多表的交集部分

2)n表连接,至少需要n-1个连接条件

3)多表的顺序没有要求

4)一般需要为表起别名

5)可以搭配前面介绍的所有子句使用,比如排序、分组、筛选等

案例
-- 1、多表等值查询
#案例1:查询女神名和对应的男神名
#案例2:查询员工名和对应的部门名

-- 2、为表起别名
#查询员工名、工种号、工种名

-- 3、两个表的顺序可以调换
#查询员工名、工种号、工种名

-- 4、可以加筛选
#案例1:查询有奖金的员工名、部门名
#案例2:查询城市名中第二个字符为o的部门名和城市名

-- 5、可以加分组
#案例1:查询每个城市的部门个数
#案例2:查询有奖金的每个部门的部门名和部门的领导编号和该部门的最低工资

-- 6、可以加排序
#案例:查询每个工种的工种名和员工的个数,并且按员工个数降序

-- 7、可以实现三表连接?
#案例1:查询员工名、部门名和所在的城市
#案例2:查询员工名、部门名和所在的城市,要求城市名称以s开头,并且按照部门名称降序。

4). 非等值连接

执行初始化脚本 job_grades.sql,创建并插入以下数据。

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

5). 自连接

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

8.5 SQL99语法

SQL92和SQL99的区别

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

8.5.1 内连接

1). 语法
SELECT 查询列表

FROM 表名1 别名 [INNER] JOIN  表名2 别名

ON 连接条件

WHERE 筛选条件

GROUP BY 分组列表

HAVING 分组后筛选

ORDER BY 排序列表;
2). 等值连接
-- 1.简单连接
#案例:查询员工名和部门名

-- 2.添加筛选条件
#案例:查询部门编号>100的部门名和所在的城市名

-- 3.添加分组
#案例:查询每个城市的部门个数

-- 4.添加分组+排序
#案例:查询部门中员工个数>10的部门名,并按员工个数降序
3). 非等值连接
#案例:查询部门编号在10-90之间的员工的工资级别,并按级别进行分组
4). 自连接
#案例:查询员工名和对应的领导名

8.5.2 外连接

1). 说明

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

2). 应用场景

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

3). 用法

左连接的话,left join左边为主表;

右连接的话,right join右边为主表;

左/右外连接 = 内连接查询的结果 + 主表中有而从表中没有的记录

全外连接 = 内连接查询的结果 + 表1中有但表2中没有的记录 + 表2中有但表1中没有的记录

4). 语法
select 查询列表

from1 别名

left | right | full [outer] join2 别名

on 连接条件

where 筛选条件;
5). 左外连接 left outer join
SELECT  FROM emp e LEFT OUTER JOIN dept d ON e.deptno=d.deptno;

注意:OUTER可以省略

左连接是先查询出左表(即以左表为主),然后查询右表,右表中满足条件的显示出来,不满足条件的显示NULL。

6). 右外连接 right outer join
SELECT  FROM emp e RIGHT OUTER JOIN dept d ON e.deptno=d.deptno;

右连接就是先把右表中所有记录都查询出来,然后左表满足条件的显示,不满足显示NULL。例如在dept表中的40部门并不存在员工,但在右连接中,如果dept表为右表,那么还是会查出40部门,但相应的员工信息为NULL。

左/右外连接 = 内连接查询的结果 + 主表中有而从表中没有的记录

#案例1:查询所有女神记录,以及对应的男神名,如果没有对应的男神,则显示为null
-- 左连接
-- 右连接

#案例2:查哪个女神没有男朋友
-- 左连接
-- 右连接

#案例3:查哪个男神没有女朋友
-- 左连接
-- 右连接

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

#案例5:查询城市名包含a字符的哪个城市没有部门,并按城市名降序
7). 全外连接 full outer join

全连接就是将表中所有记录都查询出来,且不允许重复。注:此处不支持。

全外连接 = 内连接查询的结果 + 表1中有但表2中没有的记录 + 表2中有但表1中没有的记录

#全外连接(不支持)
SELECT g.`name` , b.name 
FROM boy b 
FULL  OUTER JOIN girl  g  ON g.`boyfriend_id` = b.`id`;

8.5.3 交叉连接(笛卡尔乘积) CROSS JOIN

#交叉连接
SELECT g.`name` , b.name 
FROM boy b 
CROSS JOIN girl  g ;

8.5.4 自然连接(不常用) NATURAL JOIN

大家也都知道,连接查询会产生无用笛卡尔积,我们通常使用主外键关系等式来去除它。

而自然连接无需你去给出主外键等式,它会自动找到这一等式:

两张连接的表中字段名称和类型完全一致的列作为条件,例如emp和dept表都存在deptno列,并且类型一致,所以会被自然连接找到!

当然自然连接还有其他的查找条件的方式,但其他方式都可能存在问题!

SELECT  FROM emp NATURAL JOIN dept;  -- 内

SELECT  FROM emp NATURAL LEFT JOIN dept; -- 左外

SELECT  FROM emp NATURAL RIGHT JOIN dept; -- 右外

8.5.5 连接查询图分析

在这里插入图片描述

在这里插入图片描述

九. 子查询

9.1 概念

出现在其他语句的内部的select语句,称为子查询或内查询

里面嵌套其他select语句的查询语句,称为主查询或外查询

子查询不一定必须出现在select语句内部,只是出现在select语句内部的时候较多!

9.2 示例

select first_name from employees where department_id  > (

   	 select department_id from departments   where  location_id=1700  ) ;

9.3 分类

按子查询出现的位置进行分类:

​ 1、select后面
​ 要求:子查询的结果为单行单列(标量子查询)

​ 2、from后面
​ 要求:子查询的结果可以为多行多列

​ 3、where或having后面
​ 要求:子查询的结果必须为单列;单行子查询;多行子查询

​ 4、exists后面
​ 要求:子查询结果必须为单列(相关子查询)

其中where或having后面是重点:

​ 单行子查询

​ 特点:子查询的结果集只有一行一列

​ 多行子查询

​ 特点:子查询的结果集有多行一列

9.4 特点

1、子查询语句需要放在小括号内,提高代码的阅读性

2、子查询先于主查询执行,一般来讲,主查询会用到子查询的结果

3、如果子查询放在条件中,一般来讲,子查询需要放在条件的右侧

​ 示例:where job_id>(子查询)

​ 不能写成:where (子查询)<job_id

4、单行子查询对应的使用单行操作符: > < >= <= = <>

​ 多行子查询对应的使用多行操作符: in 、any 、all 、not in

​ 例如:

​ in : 判断某字段是否在指定列表内 x in(10,30,50)

​ any : 判断某字段的值是否满足其中任意一个

x>any(10,30,50) 相当于x>min()

x=any(10,30,50) 相当于x in(10,30,50)

x<any(10,30,50) 相当于x<max()

​ all : 判断某字段的值是否满足里面所有的

x >all(10,30,50) 相当于x >max()

x=alll(10,30,50) 无意义

x<alll(10,30,50) 相当于x<min()

9.5 案例

-- 一、放在where或having后面
-- 1.单行子查询
#案例1:谁的工资比 Abel 高?
#案例2:返回job_id与141号员工相同,salary比143号员工多的员工姓名,job_id 和工资
#案例3:返回公司工资最少的员工的last_name,job_id和salary
#案例4:查询最低工资大于50号部门最低工资的部门id和其最低工资

-- 2.多行子查询
#案例1:返回location_id是1400或1700的部门中的所有员工姓名
#案例2:返回其它部门中比job_id为‘IT_PROG’部门任一工资低的员工的员工号、姓名、job_id 以及salary
#案例3:返回其它部门中比job_id为‘IT_PROG’部门所有工资都低的员工的员工号、姓名、job_id 以及salary
#案例4:使用子查询实现城市为Toroto的,且工资>10000的员工姓名

-- 二、放在select后面
#案例:查询部门编号是50的员工个数

-- 三、放在from后面
#案例:查询每个部门的平均工资的工资级别

-- 四、放在exists后面
#案例1 :查询有无名字叫“Abel”的员工信息
#案例2:查询没有女朋友的男神信息
-- 方式1:in
-- 方式2:exists

十. 分页查询

10.1 应用场景

当页面上的数据,一页显示不全,则需要分页显示

分页查询的sql命令请求数据库服务器——>服务器响应查询到的多条数据——>前台页面

10.2 语法

		select 查询列表
		
		from1 别名
		
		join2 别名
		
		on 连接条件
		
		where 筛选条件
		
		group by 分组
		
		having 分组后筛选
		
		order by 排序列表
		
		limit 起始条目索引,显示的条目数

其中 LIMIT 用来限定查询结果的起始行,以及每页显示行数。

MySQL limit关键字 从0开始

Oracle rownum关键字

10.3 执行顺序

		from子句
		
		join子句
		
		on子句
		
		where子句
		
		group by子句
		
		having子句
		
		select子句
		
		order by子句
		
		limit子句

10.4 特点

​ ①起始条目索引如果不写,默认是0
​ ②limit后面支持两个参数
​ 参数1:显示的起始条目索引
​ 参数2:条目数

10.5 公式

假如要显示的页数是page,每页显示的条目数为size

	select *
	from employees
	limit (page-1)*size , size;

例如:
	page	     size=10
	 1      	 limit 0,10
	 2			 limit 10,10
	 3			 limit 20,10
	 4			 limit 30,10

10.6 案例

#案例1:查询员工信息表的前5条

#案例2:查询第11条——第20条的员工信息

#案例3:查询有奖金的工资最高的前三名员工名、工资、奖金、部门编号

#案例4:查询年薪最高的前10名

#案例5:使用分页查询实现,查询员工信息表中部门为50号的工资最低的5名员工信息

#案例6:查询员工表中薪资排第二的员工信息

十一. 联合查询

11.1 应用场景

当查询结果来自于多张表,但多张表之间没有关联,这个时候往往使用联合查询,也称为union查询

11.2 语法

select 查询列表 from1  where 筛选条件  
union
select 查询列表 from2  where 筛选条件  

11.3 特点

1、多条待联合的查询语句的查询列数必须一致,查询类型、字段意义最好一致
2、union实现去重查询
union all 实现全部查询,包含重复项

11.4 案例

#案例1:查询所有国家的年龄>20岁的用户信息

#案例2:查询所有国家的用户姓名和年龄

#案例3:union自动去重/union all 可以支持重复项

11.5 作业

#作业1:查询出所有女神及男神信息 
#作业2:查询出没有男朋友的女神信息和没有女朋友的男神信息

#作业3:查询出所有员工及部门信息
#作业4:查询出没有部门的员工信息及没有员工的部门信息

#作业5:查询出所有部门及区域信息
#作业6:查询出没有城市的部门及没有部门的城市信息

总结:SQL的执行顺序

手写的顺序:

SELECT 

selection_list  /*要查询的列名称*/

FROM  

table1   /*表名称,取别名*/

JOIN  

table2   /*表名称,取别名*/

ON 

condition   /*连接条件*/

WHERE 

condition /*筛选条件*/

GROUP BY 

grouping_columns /*对结果分组*/

HAVING 

condition /*分组条件*/

ORDER BY

sorting_columns /*对结果排序*/

LIMIT 

offset_start, row_count /*结果限定(分页)起始条目索引 , 显示的条目数  */

真正执行的顺序: 随着Mysql版本的更新换代,其优化器也在不断的升级,优化器会分析不同执行顺序产生的性能消耗不同而动态调整执行顺序。

下面是经常出现的查询顺序:

		from  子句
		
		join  子句
		
		on  子句
		
		where  子句
		
		group by  子句
		
		having  子句
		
		select  子句
		
		distinct  子句
		
		order by  子句
		
		limit  子句
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值