数据库--查询
一、 概念
数据库(Database)是按照数据结构来组织、存储和管理数据的仓库;随着信息 技术和市场的发展,数据管理不再仅仅是存储和管理数据,而转变成用户所需要的各 种数据管理的方式。数据库有很多种类型,从最简单的存储有各种数据的表格到能够 进行海量数据存储的大型数据库系统都在各个方面得到了广泛的应用。
数据库管理系统(Database Management System)是一种操纵和管理数据库的大 型软件,用于建立、使用和维护数据库,简称 DBMS。它对数据库进行统一的管理和 控制,以保证数据库的安全性和完整性。用户通过 DBMS 访问数据库中的数据,数据 库管理员也通过 dbms 进行数据库的维护工作。它可使多个应用程序和用户用不同的 方法在同时或不同时刻去建立,修改和询问数据库。大部分 DBMS 提供数据定义语言DDL(****Data Definition Language****)和数据操作语言DML(****Data ManipulationLanguage****)*,供用户定义数据库的模式结构与权限约束,实现对数据的追加、删除 等操作。 根据存储模型可将数据库划分为关系型数据库和非关系型数据库。 关系型数据库, 是建立在关系模型基础上的数据库,借助于集合代数等数学概念和方法来处理数据库 中的数据。 简单来说,关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织。
标准数据查询语言 SQL就是一种基于关系数据库的语言,这种语言执行对关系数据库中数据的检索和操作。 当前主流的关系型数据库有 Oracle、 DB2、 Microsoft SQL Server、 MicrosoftAccess、 MySQL 等。
Oracle Database,又名 Oracle RDBMS,或简称 Oracle。是甲骨文公司的一款 关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说 Oracle 数 据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功 能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的 适应高吞吐 量的数据库解决方案。
二、SQL 语言
SQL(Structured Query Language)为数据库的语言,在 1974 年由 Boyce【博伊 斯】 和 Chamberlin【钱伯林】 提出的一种介于关系代数与关系演算之间的结构化查询 语言,是一个通用的、功能极强的关系型数据库语言。 它包含三部分:
1. 表
表是逻辑表(概念表),不是物理表。
块(8k) --->区(连续块)-->段(连续区) -->表(多个段) ,数据段不全是表,表一定是数据段。还 有其他段:如索引段。
2、 表结构
表由表名、字段(名称+类型+约束)、记录 组成。与 java 相对应:
3、三范式
在设计数据库时,存在行业的标准,这个标准也称为条件,即范式 Normal
Form。一般遵循三个条件即可,也就是”三范式”(3NF)。
- 1NF:是指数据库表的每一列都是不可分割的基本数据项****,同一列中不能有多个值, 即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能 需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。 在第一范式(1NF)中表的每一行只包含一个实例的信息。
- 2NF:是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第 一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被唯一地区分。 为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。如 emp 表中加上了员 工编号(empno)列,因为每个员工的员工编号是唯一的,因此每个员工可以被唯一区分。 这个唯一属性列被称为主关键字或主键、主码。 同时要求实体的属性完全依赖于主关键字。 所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主 关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。 为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。 即第二范式就是非****主属性非部分依赖于主键。
image.png
- 3NF:必须先满足第二范式(2NF)。 3NF 要求一个数据库表中不包含已在其它表中已包 含的非主关键字信息。例如,存在一个部门信息表,其中每个部门有部门编号(deptno)、 部门名称、 地址等信息。那么员工信息表(emp)中列出部门编号后就不能再将部门名称、部 门地址等与部门有关的信息再加入员工信息表中。如果不存在部门信息表,则根据第三范式(3NF)也应该构建它,否则就会有大量的数据冗余。 即第三范式就是属性不依赖于其它非主属性。
简而言之,最终的目的避免数据重复冗余,
1NFà列不可再分,最小原子 (避免重复)
2NF** à**主键依赖(确定唯一);
3NFà消除传递依赖(建立主外键关联 拆分表*)
四、 SELECT
1、查询列(字段)
*select distinct |字段|表达式 as 别名 from 表 表别名
SELECT * FROM 表名;à查询某个表中所有的记录的所有字段信息
SELECT 列名 FROM 表名;à 查询某个表中所有的记录的指定字段信息
SELECT 列名1,列名2 FROM 表名;à 查询某个表中所有的记录的字段1 字段2
SELECT distinct 列名 FROM 表名;à去除重复记录
SELECT 表达式 FROM 表名;à查询表达式
SELECT xxx as 别名 FROM 表名 表别名à使用别名
1)、部分列
查询 部分字段,指定的字段名:
|
*--1)*、检索单个列 select ename from emp; *--*查询雇员姓名
*--2)*、检索多个列 select deptno,dname,loc from dept; *--*查询部门表的*deptno,dname, loc* 字段 的数据。
*--*以下查询的数据顺序不同*(*查询的字段顺序代表数据顺序*)*
select loc,dname,deptno from dept;
select deptno,dname,loc from dept;
|
2)、所有列
查询所有的字段 通配符 ( 书写方便、可以检索未知列;但是降低检索的性能)* ,数 据的顺序跟定义表结构的顺序一致:
|
*--1)*、检索所有列*1* select * from dept; *--*查询部门的所有信息
*--2)*、检索所有列*2* select deptno,dname,loc from dept; *--*查询部门的所有信息
|
3)、去除重复
|
select distinct deptno from emp; --去重
|
4)、别名 使用别名便于操作识别 、隐藏底层信息。存在字段别名和表别名:
l as: 字段别名可以使用as;表别名不能使用as l "":原样输出,可以存在 空格与区分大小写
|
select ename as "雇员 姓名" from emp;
select ename "雇员姓名" from emp;
select ename 雇员姓名 from emp;
select ename as 雇员姓名 from emp;
select ename as " Ename" from emp;
|
5)、字符串
使用’’表示字符串(注意区分””) ,拼接使用 ||
select 'my' from emp;
select ename||'a'||'-->' info from emp;
6)、虚表
用于计算表达式,显示单条记录的值
select 1+1 from dual;
7)、 null
null 遇到数字参与运算的结果为 null,遇到字符串为空串
select 1+null from dual;
select '1'||null from dual;
select 1||'2'||to_char(null) from dual;
select ename,sal*12+comm from emp;
*--nvl*内置函数,判断是否为*null,*如果为空,取默认值*0*,否则取字段实际值
select ename,sal*12+nvl(comm,0) from emp;
2、查询行(记录)
where 过滤行记录条件 ,条件有
1)、比较条件
select * from emp where deptno !=20;
select * from emp where deptno <>20;
select * from emp where sal between 800 and 950; *--between and*是成对 出现的
*--*查询 员工的年薪大于*20000*的 员工名称、岗位 年薪
*--1)*、 *nvl* select ename,job,12*(nvl(comm,0)+sal) income from emp;
*--2)*、年薪大于*20000
--*错误不能使用别名*: select ename,job,12*(nvl(comm,0)+sal) income from
emp where income>2000;
--a)*、嵌套一个*:* 查询在前 过滤在后 select ename,job,income from (select ename,job,12*(nvl(comm,0)+sal) income from emp) where income>2000;
*--b)*、不使用别名 *(*推荐*) :*过滤在前,查询在后 select ename,job,12*(nvl(comm,0)+sal) income from emp where 12*(nvl(comm,0)+sal) >2000 ;
*--*了解 *any some all
-- >=any(*值列表*)* 大于最小值 *<=any(*值列表*)*小于最大值
select * from emp where sal >=any(900,2000);
select * from emp where sal <=any(900,2000);
*-- some*与*any* 一样的效果
*-- all* 大于最大值 小于最小值
select * from emp where sal >=all(900,2000);
select * from emp where sal <=all(900,2000);
*--*查询 工种为*’SALESMAN’*的员工信息 (注意 内容区分大小写)
*--*检索 工资 大于 *2000*员工名称 岗位 工资
*--*检索 工资 小于 *3000*员工名称 岗位 工资
*--*检索 工资 *2000, 3000*员工名称 岗位 工资
*--*查询部门编号为*20*的员工名称
2)、且 或 非 and、 or、 not
select * from emp where sal>=900 and sal<=950;
*--*查询 岗位 为 *CLERK* 且部门编号为 *20*的员工名称 部门编号,工资
*--*查询 岗位 为 *CLERK* 或部门编号为 *20*的员工名称 部门编号,工资
*--*查询 岗位 不是 *CLERK* 员工名称 部门编号,工资
3)、 null
null不能使用条件判断,只能使用is :
*--*存在佣金的员工名称
select * from emp where comm is null;
*--*不存在佣金的员工名称
select * from emp where comm is not null; select * from emp where not comm is null;
4)、集合操作
Union、 Union All、 Intersect、 Minus
- Union,并集(去重) 对两个结果集进行并集操作,不包括重复行同时进行默认规则的排序;
- Union All,全集(不去重) 对两个结果集进行并集操作,包括重复行,不进行排序 ;
- Intersect,交集(找出重复) 对两个结果集进行交集操作,不包括重复行,同时进行默认规 则的排序;
- Minus,差集(减去重复) 对两个结果集进行差操作,不包括重复行,同时进行默认规则的排 序
*-*查询工资大于*1500* 或 含有佣金的人员姓名
*--union* 去除重复行
select ename from emp where sal>1500
union
select ename from emp where comm is not null;
*-- union all* 不去除重复行
select ename from emp where sal>1500
union all
select ename from emp where comm is not null;
*--*查询显示不存在雇员的所有部门号。
select deptno from dept
minus
select distinct deptno from emp
*--*查询工资大于*1500* 且 含有佣金的人员姓名
select ename,sal,comm from emp where sal>1500
intersect
select ename,sal,comm from emp where comm is not null;
5)、 like :模糊查询
模糊查询,使用通配符:
- %:零个及以上(任意个数的)的字符
- _:一个字符
- 遇到内容中包含 % _ 使用escape('单个字符')指定转义符
*-*查询员工姓名中包含字符*A*的员工信息
select * from emp where ename like '%A%';
*--*查询员工姓名中包含第二个*A*的员工名称信息
select * from emp where ename like '_A%';
*--*数据中 员工姓名中 存在 *_ % ,*如何查找:
*--1)*、编写测试数据
insert into emp(empno,ename,sal) values(1000,'t_%test',8989);
insert into emp(empno,ename,sal) values(1200,'t_tes%t',8000);
*--2)*、查找
*--*查询员工姓名中包含字符*%*的员工名称 岗位 工资 部门编号
select ename,job,sal,deptno from emp where ename like '%a%%'
escape('a');
*--*查询员工姓名中包含第二个*_*的员工名称 岗位 工资 部门编号
6)、 in 与 exists
in相当于使用or的多个等值,定值集合 ,如果存在 子查询,确保 类型相同字 段数为1,如果记录多,效率不高,用于 一些 少量定值判断上:
select * from emp where sal in(900,800)
*--*子查询*(*查询中再有查询*) in* 只能存在一个字段
select * from emp where sal in (select sal from emp e where deptno=10)
*--10*或*30*部门的雇员信息
select * from emp where deptno in(10,30);
*--*部门名称为 *SALES* 或 *ACCOUNTING* 的雇员信息
select deptno from dept where dname in('SALES','ACCOUNTING');
select * from emp
where deptno in
(select deptno from dept where dname in ('SALES', 'ACCOUNTING'));
*/** 便于理解 使用*java*思维
*while(*外层结果集*){
while(*内层结果集*){
if(emp.deptno==10){
syso("....");
}
if(emp.deptno==30){
syso("....");
}
}
}
==>in :*如果记录多,效率不高,用于 一些 少量定值判断上 **/*
exists条件为true,存在记录则返回结果,后续不再继续 比较查询,与查询的字 段无关,与记录有关:
*--exists :*条件为*true,*存在记录,则返回结果,后续不再继续 *,*与字段无关,与记录有关
*--exists* 难点*:* 外层结果集 内层结果集 关系列*(*没有关系列 *true)
/*
while(*外层结果集*){
while(*内层结果集*){
if(emp.deptno==dept.deptno||true){
syso("....");
break; //*跳出本层 *}
}
}
*/
--*无关系列 */**
while(emp* 的*14*条记录*){
while(dept*的*2*条记录*){
if(true){
syso();
break;
}*
*}
}
*/* select * from emp
where exists
(select deptno,dname from dept where dname in ('SALES', 'ACCOUNTING'));
*--*加入关系列 */**
while(emp* 的*14*条记录*){
while(dept*的*2*条记录*){
if(e.deptno=d.deptno){
syso();
break;
}
}
}
*/* select * from emp e
where exists
(select deptno,dname from dept d where dname in ('SALES', 'ACCOUNTING')
and e.deptno=d.deptno);
*/**
while(emp* 的*14*条记录*){
while(dept*的*2*条记录*){
if(e.deptno!=d.deptno){
syso();
break;
}
}
}
*/*
select * from emp e
where exists
(select deptno,dname from dept d where dname in ('SALES', 'ACCOUNTING')
and e.deptno!=d.deptno);
*--*分析以下结果
select * from emp e
where not exists
(select deptno,dname from dept d where dname in ('SALES', 'ACCOUNTING')
and e.deptno=d.deptno);
select ename, sal from emp where sal in (select sal from emp e2 where e2.sal >= 2000); select ename, sal
from emp
where exists
(select ename, sal from emp e2 where e2.sal >= 2000);
*--exists*
select empno, ename, sal from emp e1
where exists
(select empno, ename, sal, comm
from emp e2
where comm is not null
and e1.empno = e2.empno);
select empno, ename, sal from emp e1
where exists
(select empno, ename, sal, comm from emp e2 where comm is not null
and e1.deptno = e2.deptno );
3、排序
使用 ORDER BY 排序,排序不是真实改变存储结构的顺序,而是获取的集合的 顺序。
- 顺序 :asc(默认) desc
- 多字段: 在前面字段相等时,使用后面的字段排序
- 空排序: 降序为 desc,注意 null 为最后
*--*按工资降序
select * from emp order by sal desc;
*--null*问题
select * from emp order by nvl(comm,0),comm desc;
select * from emp order by comm nulls first;
*--*查询雇员姓名,年薪 按佣金排序 默认为升序*(asc)*,降序为*desc*,注意*null*为最后 select ename,(sal+nvl(comm,0))*12,comm total from emp order by comm desc;
*--*查询雇员姓名,年薪 按佣金排序 默认为升序*(asc)*,降序为*desc*,注意*null*为最后 select ename,(sal+nvl(comm,0))*12,comm total from emp order by comm desc;
*--*对部门编号为 *20* 或*30*的雇员,工资*+*佣金 进行升序排序,如果相同,则按姓名降序。
*--1*、查询*20*、 *30* 雇员
select * from emp where deptno in(20,30);
*--2*、工资*+*佣金排序
select ename,sal,comm,sal+nvl(comm,0) c from emp
where deptno in(20,30) order by c;
*--3*、多个字段排序使用*,* 排序的字段可以使构建出来的虚拟的字段
select ename,sal,comm from emp
where deptno in(20,30)
order by sal+nvl(comm,0),ename desc;