DQL
Posted zhuchangwu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DQL相关的知识,希望对你有一定的参考价值。
常见的sql分类五种分类
- DDL (Data Definition Language)数据库定义语言
- DML (Data Manipulation Language)数据操作语言
- DCL (Data Control Language)数据控制语言
- TCL (Transactional Control Language) 事务控制语法
- DQL (Data Query Language) 数据查询语言
有时候会把DQL归入到DML中, 因为DML常见的操作是针对数据表中数据的 增删改 ,而查数据的DQL,同样是基于表中数据级别的操作,所以真的把DQL归入到DML也说的过去,但是DQL 单条select语句的复杂程度就远远高于 DDL DML DCL TCL中的任意一种,所以我单独整理出来
Select知识图谱
如何写查询sql?
-- 一条查询语句,最容易确定就是 要查询的结果是什么! 也就是 select 后面紧跟的信息;
-- 数据从哪里获取? from XXX表
-- 最简单的查询 ,`查询某某某,且表中的字段` 简单的没话说
-- 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
例:查询有员工的部门信息:
select * from DEPT d where exists (select * from emp e where d.DEPTNO=e.DEPTNO);
虚表/伪标
dual是Oracle中的虚表,它的存在主要是为了补全语法结构(select XXX 后面没有from 的话,报错 ), 里面只有一行一列 存着个X
select 1+1; // 在Oracle中会报错, 而mysql不会报错
select 1+1 from dual; // 添加From 关键字+ 虚表 dual 补全语法结构
伪列 rownum
就是Oracle 特有的用来表示行号的, 默认起始值为1 ,有了结果再 +1
-- 练习; 找到员工表中,工资最高的前三名 -- 添加上一个条件 rownum<4 就行
-- 空格+新表名 里面的表可以用里面的表的别名 反之不可以
select ROWNUM ,table1.* from ( select * from EMP e order by sal desc) table1 where rownum<4;
-- 练习: 查询员工表中的 薪水大于本部门的平均薪水的员工
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
select * from (select rownum hanghao,emp.* from EMP) tt where tt.hanghao between 1 and 5;
伪列 rowid
伪列,每行记录存放的真实物理地址
简单使用,查看emp表里面每行的物理地址
select rowid ,e.* from EMP e;
-- 去除(删除) 表中的重复记录
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号部门下的员工
select * from EMP where emp.sal>1500 or EMPNO=20;
-- 并集 union 去重并且排序
-- 并集 union all 不去重
---差集 minus A minux B A-B
-- 注意点:
-- 1.列的类型要一致
-- 2. 按顺序书写
-- 3. 列的数量要一致,如果不一致,会用空值填充
用法
select XXX union , union, minus select XXX;
别名查询
as关键字可以省略
select ename as "姓 名", sal as 工资 from emp;
取出重复数据
distinct关键字,在select之后
查询中的四则运算
- select 显示字段 ... ; 显示字段如果是数字,Oracle支持四则运算
- 注意:null值, 不可以做四则运算-- 解决 nvl(P1,P2)函数,若P1为null,那么取P2的值
select sal*12 + comm from EMP;
select sal*12 + nvl(comm,0) from EMP;
字符串的拼接符
- Oracle中使用 || 进行字符串的拼接
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‘
// 查询名字中包含% 的学生的信息
select * from emp where ename='%/%%' escape '/';
排序:order by
- 升序:asc
- 降序:desc
注意点: 排序时,空值默认会排到前面去
解决:
// 默认
select * from emp order by comm desc nulls first;
// 解决:
select * from emp order by comm desc nulls last;
函数
- 单行函数
- 对行中的某一个值进行处理
- 数值函数
- 字符函数
- 日期函数
- 转换函数
- 通用函数
- 对行中的某一个值进行处理
数值函数:
向上取整
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
字符函数:
- 截取字符串 : substr("被操作的字符串",起始索引,长度)
注意点: 不管起始索引从0开始还是1开始,都是从第一个字符开始算
- 获取字符串的长度: length(‘sdfghj‘)
注意从1开始计数
- 去除字符串左右两边的空格
trim(‘ ghj ‘)
日期函数
-- 查询今天的日期
select sysdate from dual;
--三天后
select sysdate +3 from dual;
-- 查询三个月后的日期
select add_months(sysdate,3) from dual;
-- 注意点: 时间是本地服务器上的时间
转换函数
- 转数字: 字符串+数字 = 数字 <==> to_number(‘字符串‘)
- 转字符串: to_char(数字/日期,‘转换后的格式(yyyy-MM-dd / $999,999,.999)‘)
- 字符转日期: to_date(‘字符串‘,‘准换后的格式‘)
通用函数
- nv1(p1,p2) // 如果 p1==null 返回 p2
- nv12(p1,p2,p3) // 如果 p1==null 返回p3 否则返回 p2
- nullif(p1,p2) // 如果 p1==p2 返回null 否则返回p1
- coalesce(p1,p2....) // 返回第一个不为空的值
- 多行函数
- 对所有列进行处理
- max()
- min()
- count()
- sum()
- avg()
- 对所有列进行处理
注意点: avg() 平均值 受空值影响
// 求工资平均值
select avg(工资)/ count(1) from 员工表;
条件表达式
- Oracle 和 Mysql 都有 --- case when XXX then XXX
给表中人取别名,并显示
select ename from emp;
select
case ename
when 'W' then '哈哈' -- 如果是W 改为 哈哈
when 'Q' then '呵呵' -- 如果是 Q 改为 呵呵
else
'哇哇' -- 其他改为 哇哇
end '姓名' -- 表名改为 姓名
- Oracle 特有的 --- decode()
select decode(ename,'ALLEN','哈哈','名字') from EMP;
-- 如果是 W 改为哈哈 R 改为 哈哈
select decode(ename,'W','哈哈','R','哈哈') from emp;
分组表达式 group by
-- 写法
select 分组条件 分组之后的操作 from 表名 group by 分组的条件 having 条件过滤
-- 分组统计所有部门的平均工资,找出平均工资大于2000的部门
select DEPTNO, avg(SAL) from EMP group by DEPTNO having avg(SAL)>2000;
-- 错误写法
select DEPTNO, avg(SAL) avg from EMP group by DEPTNO having avg>2000;
- 注意点1 : select后面的 是不能 声明 别名的!!!
原因: sql的书写顺序和执行顺序是不同的
-- 书写顺序
select [分组条件] [字段] [*] [函数操作] from 表名 where 条件 group by 分组条件 having 过滤条件 order by
-- 执行顺序
from ..where...group by ... having...order by select
- 注意点2: select + 分组条件 + 其他操作 其中的 分组条件只能有一个
- 注意点3: where 和 having 和区别
-- where 后面不能接 聚合函数
-- having在group by 后面执行 可以接聚合函数
以上是关于DQL的主要内容,如果未能解决你的问题,请参考以下文章