DQL

常见的sql分类五种分类

  1. DDL (Data Definition Language)数据库定义语言
  2. DML (Data Manipulation Language)数据操作语言
  3. DCL (Data Control Language)数据控制语言
  4. TCL (Transactional Control Language) 事务控制语法
  5. DQL (Data Query Language) 数据查询语言

有时候会把DQL归入到DML中, 因为DML常见的操作是针对数据表中数据的 增删改 ,而查数据的DQL,同样是基于表中数据级别的操作,所以真的把DQL归入到DML也说的过去,但是DQL 单条select语句的复杂程度就远远高于 DDL DML DCL TCL中的任意一种,所以我单独整理出来

Select知识图谱

如何写查询sql?

– 一条查询语句,最容易确定就是 要查询的结果是什么! 也就是 select 后面紧跟的信息;
– 数据从哪里获取? from XXX表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
-- 最简单的查询 ,`查询某某某,且表中的字段` 简单的没话说
-- select XXX from 表名

-- 如果让查询 查询某某某 ,出现了一个 的 结果就不一样了
-- 内连接:
-- 隐式内连接
-- 等值内连接
-- 不等值内连接
-- 自表连接(查询表中的A字段需要B字段辅助)
-- 显示内连接
-- 关键字 inner join on XXX=YYY

-- 外连接:
-- 左外连接
-- left join on : 特点, 显示的结果为左表中的全部数据加上右表中匹配上的数据(没有的字段为null)
-- 右外连接
-- right join on : 特点, 右表中的全部数据+ 左表中匹配上的数据 (没有的字段为null)
-- 自然连接 antural join
-- 默认去除笛卡尔积的条件是 两个表的相同字段 相等(存在多个字段,多个字段分别相等)

-- 如果是我们查询某某的某某某 ,一般是子查询
-- 单行子查询
-- 特点: 查询的结果是一行一列
-- 通用的操作符: > >= < <= != <>

-- 多行子查询
-- 特点: 查询的结果是多行多列
-- 常用的关键字: or , in , all , exits , not in (<>all) , any
-- 注意点: 多行子查询要规避null, not in (子查询) 这时子查询结果如果有null, 整个的结果为空
-- 错误实例: select * from emp where empno not in (select mgr from emp);
-- 错误点: 因为子查询结果中存在null,所以和前面的关键字 not in 结合,结果为 空
-- 解决: 加添加, where mgr is not null

exits 关键字

– exists (查询语言) , 在大数据级别下,它的效率很高!!!
– 查询到结果 true 否则 false

例:查询有员工的部门信息:

1
select * from DEPT  d where exists (select * from emp e where d.DEPTNO=e.DEPTNO);

虚表/伪标

dual是Oracle中的虚表,它的存在主要是为了补全语法结构(select XXX 后面没有from 的话,报错 ), 里面只有一行一列 存着个X

1
2
3
select 1+1; // 在Oracle中会报错, 而Mysql不会报错

select 1+1 from dual; // 添加From 关键字+ 虚表 dual 补全语法结构

伪列 rownum

就是Oracle 特有的用来表示行号的, 默认起始值为1 ,有了结果再 +1
– 练习; 找到员工表中,工资最高的前三名 – 添加上一个条件 rownum<4 就行

1
2
-- 空格+新表名  里面的表可以用里面的表的别名  反之不可以
select ROWNUM ,table1.* from ( select * from EMP e order by sal desc) table1 where rownum<4;

– 练习: 查询员工表中的 薪水大于本部门的平均薪水的员工

1
2

select * from (select DEPTNO ,avg(sal) avgsal from EMP group by deptno) table1 , emp where emp.DEPTNO=table1.DEPTNO and emp.sal>table1.avgsal;

– 在Oracle中的分页
– mysql中的分页使用limit
– oracle只能使用rownum

1
select * from (select rownum hanghao,emp.* from EMP) tt where tt.hanghao between 1 and 5;


伪列 rowid

伪列,每行记录存放的真实物理地址

简单使用,查看emp表里面每行的物理地址

1
select rowid ,e.* from EMP e;

– 去除(删除) 表中的重复记录

1
2
3
4
5
6
7
8
9
create table p(name varchar2(20));
insert into p(name) values ('张三');
insert into p(name) values ('张三');
insert into p(name) values ('李四');

select ROWID from p;

-- 删除,rowid 是从小到大排序的, 我们只要 rowid 小的
delete from p where p.ROWID>(select min(rowid) from p p2 where p.name=p2.name);

并集运算

– 交并补

– 例: 工资大于1500 ,或者20号部门下的员工

1
select * from EMP where emp.sal>1500 or EMPNO=20;

– 并集 union 去重并且排序
– 并集 union all 不去重
—差集 minus A minux B A-B
– 注意点:
– 1.列的类型要一致
– 2. 按顺序书写
– 3. 列的数量要一致,如果不一致,会用空值填充

用法

1
select XXX union , union, minus select XXX;

别名查询

as关键字可以省略

1
select ename as "姓   名", sal as 工资 from emp;

取出重复数据

distinct关键字,在select之后

查询中的四则运算

  • select 显示字段 … ; 显示字段如果是数字,Oracle支持四则运算
  • 注意:null值, 不可以做四则运算– 解决 nvl(P1,P2)函数,若P1为null,那么取P2的值
1
2
3
select sal*12 + comm from EMP;

select sal*12 + nvl(comm,0) from EMP;

字符串的拼接符

  • Oracle中使用 || 进行字符串的拼接
1
2
3
4
select ENAME from EMP;

// 单引号是使用值, 双引号取别名使用
select '姓名:'||ENAME from EMP;

在mysql和oracle 中都有concat(str1,str2)函数,用于字符串拼接

条件查询(where 后面的条件)

  • 关系运算符: > >= < <= != <>
  • 逻辑运算符: and or not
  • 其他运算符:
    • like % 匹配多个字符 _ 匹配单个字符
    • in
    • between..and…
    • is null
    • is not null

Oracle处理转义字符:escape 'X'

1
2
// 查询名字中包含% 的学生的信息
select * from emp where ename='%/%%' escape '/';

排序:order by

  • 升序:asc
  • 降序:desc

注意点: 排序时,空值默认会排到前面去
解决:

1
2
3
4
// 默认
select * from emp order by comm desc nulls first;
// 解决:
select * from emp order by comm desc nulls last;

函数

  • 单行函数
    • 对行中的某一个值进行处理
      • 数值函数
      • 字符函数
      • 日期函数
      • 转换函数
      • 通用函数

数值函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
向上取整
select ceil(45.8) from dual; //46
select ceil(-45.8) from dual; //45 如果是负数,结果: -直接去小数部分

去除小数
select floor(45.8) from dual; //45

保留指定位
select round(45.82,1) from dual; // 45.8
select round(45.8,0) from dual; // 46
select round(45.8,-1) from dual; // 50
select round(45.8,-2) from dual; // 0

截断
select trunc (45.999,2) from dual; // 45.99

字符函数:

  1. 截取字符串 : substr(“被操作的字符串”,起始索引,长度)

注意点: 不管起始索引从0开始还是1开始,都是从第一个字符开始算

  1. 获取字符串的长度: length(‘sdfghj’)

注意从1开始计数

  1. 去除字符串左右两边的空格

trim(‘ ghj ‘)

日期函数

1
2
3
4
5
6
7
8
-- 查询今天的日期
select sysdate from dual;
--三天后
select sysdate +3 from dual;
-- 查询三个月后的日期
select add_months(sysdate,3) from dual;

-- 注意点: 时间是本地服务器上的时间

转换函数

  1. 转数字: 字符串+数字 = 数字 <==> to_number(‘字符串’)
  2. 转字符串: to_char(数字/日期,’转换后的格式(yyyy-MM-dd / $999,999,.999)’)
  3. 字符转日期: to_date(‘字符串’,’准换后的格式’)

通用函数

  1. nv1(p1,p2) // 如果 p1==null 返回 p2
  2. nv12(p1,p2,p3) // 如果 p1==null 返回p3 否则返回 p2
  3. nullif(p1,p2) // 如果 p1==p2 返回null 否则返回p1
  4. coalesce(p1,p2….) // 返回第一个不为空的值

  • 多行函数
    • 对所有列进行处理
      • max()
      • min()
      • count()
      • sum()
      • avg()

注意点: avg() 平均值 受空值影响

1
2
// 求工资平均值
select avg(工资)/ count(1) from 员工表;

条件表达式

  1. Oracle 和 Mysql 都有 — case when XXX then XXX
1
2
3
4
5
6
7
8
9
10
11
给表中人取别名,并显示

select ename from emp;

select
case ename
when 'W' then '哈哈' -- 如果是W 改为 哈哈
when 'Q' then '呵呵' -- 如果是 Q 改为 呵呵
else
'哇哇' -- 其他改为 哇哇
end '姓名' -- 表名改为 姓名
  1. Oracle 特有的 — decode()
    1
    2
    3
    4
    select decode(ename,'ALLEN','哈哈','名字') from EMP;

    -- 如果是 W 改为哈哈 R 改为 哈哈
    select decode(ename,'W','哈哈','R','哈哈') from emp;

分组表达式 group by

– 写法

1
select 分组条件 分组之后的操作 from 表名 group by 分组的条件 having 条件过滤

– 分组统计所有部门的平均工资,找出平均工资大于2000的部门

1
select DEPTNO, avg(SAL) from EMP group by DEPTNO having avg(SAL)>2000;

– 错误写法

1
select DEPTNO, avg(SAL) avg from EMP group by DEPTNO having avg>2000;

  • 注意点1 : select后面的 是不能 声明 别名的!!!

原因: sql的书写顺序和执行顺序是不同的

– 书写顺序

1
2
3
4
5
select [分组条件] [字段] [*] [函数操作] from 表名 where 条件 group by 分组条件 having 过滤条件 order by
```
-- 执行顺序
```sql
from ..where...group by ... having...order by select

  • 注意点2: select + 分组条件 + 其他操作 其中的 分组条件只能有一个
  • 注意点3: where 和 having 和区别

– where 后面不能接 聚合函数

– having在group by 后面执行 可以接聚合函数