第一章 数据库 3
一、认识数据库 3
1.1概念 3
1.2安装 3
1.3知识点 4
1.4使用客户端链接数据库PLSQL 5
二、关系数据库(database manager system) 5
三、DML语言:数据库管理语言 6
3.1Oracle基本操作 6
3.2用户管理 7
第二章 Oracle数据库 7
一、表(Tabel) 8
1.1理解表 8
1.2表结构 8
二、Scott用户表 9
2.1查看用户表 9
2.2查看表结构 9
三、数据库设计原则——三范式 10
四、SELECT 10
4.1查询语法 10
4.2查询列 10
4.3查询知识点 11
五、Oracle函数 16
5.1单行函数 16
5.2组函数 18
六、多表查询 21
6.1Oracle多表查询操作 21
6.2多表查询的笛卡尔积现象 21
6.3自连接 22
6.4子查询 23
6.5外连接 23
七、Oracle技术与符合查询 26
7.1分页技术 26
7.2合并查询 26
7.3数据库的DML操作 26
互联化+时代的到来,需要持久化数据呈现井喷式发展,常规io操作虽然可以满足持久化的需求,但是,对于持久化的目的,对数据的操纵,显然力不从心,且操作的复杂度很大,不利于大规模的发展,审时度势,数据库应运而生。
数据库是数据管理的重要技术,也是计算机的重要分支。由于数据库具有数据化结构,最低冗余度、较高的程序与数据独立性,易于扩展、易于编制应用程序等有点,较大的信息系统都是建立在数据库设计之上的。从一般管理扩大到计算机辅助技术、人工智能以及科技计算等领域。
随着数据库技术的发展,计算机技术也随着得到了很大的发展,数据库为我们提供了可以快速存储以及检索的便利,它也为近几年软件可以如此普及贡献不小的力量。
理解什么是数据库:当我们在写String s = “Hello world”时,程序运行时,数据存储在内存中,程序结束时,数据变消失不再存在。如果我们想下一次运行时,还能读取到这个数据,那么就会想办法将这个数据存储在磁盘文件上,用到我们之前学习的知识,我们学过IO,我们可以用序列化将数据存到本地磁盘文件上,取出时用反序列化,但是这只能存储小数据,所以这时候出现了——数据库。
本次教学中使用数据库:数据库软件:Oracle 11g XE 版本(大学通用版)。Oracle 11g EX与Oracle 11g的区别:本质上没有区别,区别是数据库的创建,XE默认给了一个数据库,企业版会由公司自行创建数据库,而XE不能创建。XE便于安装,而Oracle 11g一次没有安装成功就需要重装系统。
广义:存储数据的系统。
狭义:利用磁盘文件进行有规律的存储数据。(数据不一定全部存储在磁盘文件中,还能存到内存数据库redis(所谓的缓存,也就是存到内存中去))
持久化:将内存中数据,永久的保存到磁盘中,这个过程称为持久化过程。
确保安装时账户是管理员(不是必须的)。
解压数据库,打开DISKI文件夹,setup.exe双击运行,管理员口令123。(尽量不要安装在C盘)
测试数据库是否安装成功:打开dos窗口,执行以下代码:
1.打开doe窗口 输入:sqlplus /nolog sqlplus表示登录平台 /nolog表示无参数登录 2.创建scott用户,使用tiger密码登录。使用用户名登:conn scott/tiger@xe 语法结构:conn [用户名]/[密码]@xe; conn是链接的英文缩写。为什么使用scott用户:因为在11g版本以前都会有一个scott用户,这个scott用户便是oracle数据库的开发人员。@是登录到某个数据库,xe是我们安装的Oracle 11g EX默认创建的数据库名称,以后如果要登录到xxx数据库,便是@xxx。 3.测试数据库是否链接成功(查询数据库中的表):selcet * from emp; 表格内容正常显示也就代表安装成功 4.完成 |
sqlplus /nolog conn / as sysdba; create user scott identified by tiger; GRANT CONNECT,RESOURCE,UNLIMITED TABLESPACE TO SCOTT IDENTIFIED BY TIGER; 取消区分大小写: alter system set sec_case_sensitive_logon=false; 导入scott.sql @C:\oraclexe\app\oracle\product\11.2.0\server\rdbms\admin\scott.sql 查询所有用户: select username from all_users; 登录: conn scott/tiger; 在上述成功的前提下: conn scott/tiger@xe; |
1.3.1常见的数据库
Oracle、Mysql、DB2(很大,一般用于金融类型的公司),这三种数据库市场占有率90%以上,最核心的是Oracle和Mysql。
1.3.2数据库的分类
小型数据库access、foxbase:数据库本身容量小,操作结构简单,不安全。负载量小,用户大概100人以内(留言板、信息管理系统),成本在千元之内,对安全性要求不高。
中型数据库sqlservler、mysql:负载量,日访问在5000~10000,成本在万元以内(商务网站),满足日常安全需求。
大型数据库sybase、db2、oracle:海量负载,可以处理海量数据(sybase 1.3.3数据库选的原则 原则:考虑项目的负载量、经济成本、安全性。选择时不一定要选择最好的,但是需要选择最合适的。 1.4.1更改配置 PLSQL\instantclient_11_2目录下的tensnames.ora文件,打开后除了注释,值保留一下代码,并匹配数据库IP和数据库实例名称。20.45.128.26数据库IP地址,OO数据库示例名称。 注意:这里更改配置后,我们在dos命令中输入的就不再是conn scott/tiger@xe;而是conn scott/[email protected]; 127.0.0.1XE = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = XE) ) ) 1.4.2配置环境变量 NLS_LANG = SIMPLIFIED CHINESE_CHINA.ZHS16GBK TNS_ADMIN = G:\PLSQLDeveloper\PLSQL\instantclient_11_2 1.4.3PL/SQL Developer 环境设置 位置:工具 -> 首选项 -> 链接 设置: Oracle主目录名 = G:\PLSQLDeveloper\PLSQL\instantclient_11_2 OCI库 = G:\PLSQLDeveloper\PLSQL\instantclient_11_2\oci.dll 检测是否链接数据库,打开客户端,查看窗口左上角,是否为登录的数据库实例名,未链接成功左上角为:未登录。 关系数据库,是建立在关系模型基础上的数据库。借助于集合代数等数学概念和方法来处理数据库中的数据。标准数据查询语言SQL就是一种基于关系数据库的语言,这种语言执行对关系数据库中数据的检索和操作。关系模型由关系数据结构、关系操作集合、关系完整性约束三部分组成。 标准数据查询语言SQL:”第四代语言”,更加接近人的自然语言。 关系模型就是指二维表格模型,因而一个关系型数据库就是由二维表及其之间的联系组成的一个数据组织。 Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说 Oracle 数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库解决方案。 SQL(Structured Query Language)结构化查询语言,为数据库的语言,在1974年由Boyce和Chamberlin提出的一种介于关系代数与关系演算之间的结构化查询语言,是一个通用的、功能极强的关系型数据库语言。 对用户实现管理的语句,并不是SQL语言,而是DML语言。DML语言:数据库管理语言database manager language。对用户的添加、删除、解锁、锁定等。 3.1.1进入数据库服务 语句:sqlplus /nolog 说明:登录到数据库示例上 3.1.2数据库连接指令 关键词:conn-->connection 语法结构:conn 用户名/密码@网络服务名 语句:conn scott/tiger@xe;(不是SQL语句,只是一个数据库的登录语句) xe表示数据实例--数据库名称 3.1.3显示当前用户名 语句:show user; 示例:USER 为 “SCOTT” 3.1.4退出 语句:exit 3.1.5 & 占位符 说明:可以替代变量,而该变量在执行时,需要用户输入()。 SQL语句:select * from emp where job = ‘&job’; 输入job的值:SALESMAN SQL> select * from emp 2 ; //表示第二行 而不是只有2条数据。sql语句一定以“;”结束此句。当没有输入;,按了回车,就会显示一个2,代表第二行输入。 实现用户管理的账户,必须有管理用户的权限(Oracle对权限的控制非常严),才能实现用户管理。什么样的账户具有管理用户的权限——以下这两种登录方式都是以系统管理员身份(sys账户)登录数据库,是oracle系统超级管理员。具有用户创建的权利。 conn / as sysdba; conn sys/123 as sysdba; 关于用户角色与权限详解:http://www.cnblogs.com/chinhr/archive/2011/10/10/2206631.htm。 用户创建:用有管理用户权限的账户创建一个新的账户,但是在没有给这个心账户权限的时候,还不能使用它登录。 create user [用户名称] identified by [密码]; 用户已创建。 删除用户:一般以dba的身份去删除某个用户,如果用其他用户去删除用户则需要具有drop user的权限。注:如果该用户的账户下已有数据信息(已建表etc..)在删除的时候同时删除表数据信息,可以在后面加cascade,就可以删除这个需要删除的用户下的表数据信息。 drop user [用户名] [cascade]; 用户已删除。 用户授权管理:给一个用户赋权限使用命令grant,回收权限使用命令revoke。grant dba to wb;,就是赋予dba权限给wb。 grant [权限] to [需要授权的用户名]; 授权成功。 用户的状态:锁定用户、解锁用户。 alter user [用户名] account [lock/unlock]; 用户已更改。 oracle数据库,关系型数据库,基于关系模型设计。oracle,关系是如何维护?通过数据库中的二维表进行维护。SQL:结构化查询语言。(查询、增加、修改、删除),最难点:查询(单表、多表查询)。 ID NAME AGE HOBBISE S001 Daming 23 swimming S002 Kitty 12 running 行:表示记录(实际中的数据),一行代表一条记录。列:字段(属性) 字段名 与 字段值。表中记录与java中实例化对象什么关系?——表中一条记录,等同于java中一个实例化对象。java中创建对象的四种方式:new 反射 反序列化 clone。 1.表是从属于用户的:select * from scott.emp;。查询表(用户名.表名),当前用户查询自己的表时,用户名可以省略,其他用户查询别的用户表,不能省略,同时必须存在权限。 2.表是逻辑表(概念表),不是物理表。块(最小的储存单位是块,8k)-->区(连续块)-->段(连续区)-->表(多个段),数据段不全是表,表一定是数据段。还有其他段:如索引段。数据库存储的基本单位:block(块)-->8k。不同的数据库中块的大小不一样。8k是oracle下的默认值,可以改。 表名、字段(字段名,类型,约束)、记录组成。 DB JAVA 表名 类名 字段名 属性名 字段类型: 属性类型: 基本类型 引用类型 记录:数据 对象:new 1.2.1char与varchar2区别 将”char”用varchar2类型的变量去存储,开辟了4个空间,这时候,我们想给这个变量重新赋值”ch”,只需要2个空间,那么varchar2会自动删除多余的空间。但是char不会。所以:varchar2可变字符串,char不可变。没有优劣之分,只有适用于不同的场合。 varchar2查询模式,在不确定长度下,查询数据需要按照长度变化进行比对——查询的时间复杂度提升。用时间换空间。 char查询模式:在定长下查询数据,时间复杂度降低,存在冗余,浪费空间,孔家你的复杂度提升。用空间换时间。 场景: 用户登录 手机号登录----->? 手机号定长,手机号属于设点数据(会经常查找),这时候应该选用char。 SQL:select tabel_name from tabs; 查看该用户下所有的表 oracle命令不区分大小写(SELECT与select),存储数据内容,区分大小写。 DML:desx [表名]; 查询表的结构 表名 dept 主键 deptno 字段名 中文 类型 为空 默认值 其他说明 deptno 部门编号 number(2) 否 主键 dname 部门名称 varchar2(14) loc 地址 varchar2(13) 备注 表名 emp 主键 empno 字段名 中文 类型 为空 默认值 其他说明 empno 雇员编号 number(4) 否 主键 ename 雇员名称 varchar2(10) job 岗位工种 varchar2(9) mgr 上级|经理人 number(4) hiredate 雇佣日期 date sal 工资 number(7,2) comm 奖金|津贴 number(7,2) deptno 部门编号 number(2) 外键,dept 表的 备注 表名 salgrade 主键 字段名 中文 类型 为空 默认值 其他说明 grade 等级 number losal 最低 number hisal 最高 number 再设计数据库时,存在行业的标准,这个标准也称为条件,即范式Normal Form。一般遵循三个条件即可,也就是“三范式”。 第一范式:原子性:每一列都是不可分割的基本数据项。所谓的不可分割,是相对于需求来说:查询用户所属的市。所以针对需求,我们选用第二个方案。“表内字段”。 具体: 1.adress 安徽省合肥市 2.province 安徽省、city 合肥市 第二范式:主键依赖:主键是确保表中的记录唯一,表中的每个字段都与主键有直接关联。“表内字段之间”。(通常可以充当主键的:流水编号[自动增长列]、表中唯一性字段、UUID) 第三范式:主外键依赖:本表外键是其他表中的主键。“表之间的关系”。 语法 所有的查询,都会使用一个关键词,select。 结构 select * from [表名]; 按照指定列查询 select [查询列] from emp; select ename form emp; 按照多列列查询 select [查询列1] , [查询列2] from emp; select ename,job from emp; 全部列查询 select * from emp; select deptno, dname, loc form dept; 注意: select * from dept; == SELECT * FROM dept; SQL语句本身不区分大小写。 注释: 概念:解释说明。分类:单行注释( -- 这就被注释了,被注释后字体显示红色斜体)、多行注释(/* 我被注释了 */)。 条件查询 where 查询 SMITH 的 雇员编号 薪水 岗位 select empno, sal, job from emp where ename = 'SMITH'; 查询 SMITH 的 部门编号 select ename ,deptno from emp where ename = 'SMITH'; 别名”雇员名称” 便于显示 字段后添加双引号 查询 SMITH 的部门编号 与 雇员姓名 select ename "雇员名称", deptno "部门编号" from emp where ename = 'SMITH'; 去重问题distinct 加在被去除的字段前面 查询 雇员表中 雇员部门编号的种类 select distinct deptno from emp; select distinct m.ename "上级", m.sal "上级工资" from emp e ,emp m where e.mgr = m.empno and m.sal > 3000; 等值查询 如:where ename = 'SMITH'; 不等值查询:单个条件:> < >= <= != <> = 多个条件:需要条件链接 and同时满足 or满足其中任何一条 and 场景:显示薪资大1200的雇员姓名、岗位、部门编号 查询条件1个 select e.ename , e.job , e.sal from emp e where e.sal > 1200; 场景:显示 薪资大于1200 小于2000 雇员姓名 岗位 以及部门编号 查询条件 2个 需要两个都满足 使用and 链接 select e.ename , e.job , e.sal from emp e where e.sal > 1200 and e.sal < 2000; or 场景:查询 部门编号30 或者 薪资大于2000雇员信息 select * from emp e where e.deptno = 30 or e.sal > 2000; 场景:查询部门编号40中 薪资大于 1500的雇员姓名 select e.ename from emp e where e.deptno = 40 and e.sal > 1500; 范围查询 between 【范围1】 and 【范围2】 是一个闭区间查询[范围1,范围2] 场景:显示 薪资大于1200 小于2000 雇员姓名 岗位 以及部门编号 select * from emp e where e.sal between 1200 and 2000; 场景:显示 薪资大于等于1200 小于2000 雇员姓名 岗位 以及部门编号 select * from emp e where e.sal >= 1200 and e.sal < 2000; != 场景:查询 部门不为40的 雇员姓名 岗位 薪资 select ename , job , sal from emp where emp.deptno != 40; select ename , job , sal from emp where emp.deptno <> 40; {不推荐} 函数nvl(字段名,默认值) 处理 null nvl(comm,0) 不为空显示comm的值 为空显示0 Oracle中内置函数 查询出 部门编号为30的雇员年薪 年薪 = 月薪*12 + 奖金 select e.ename, ( nvl(e.sal,0)*12 + nvl(e.comm,0) ) "年薪" from emp e where e.deptno = 30; 补充:null 处理 场景:查询津贴 为 null 职员信息 select * from emp where comm is null; 场景:查询津贴 不为 null 职员信息 select * from emp where comm is not null; 场景:查询部门30 且没有奖金的职员(null或0) select * from emp where emp.deptno = 30 and nvl(comm,0) = 0; 虚表dual 在数据库中值包含一列 一条记录一个字段 不作为数据存储用 作用:做计算使用 使用sql计算1+2 select 1+2 from dual; 注:SQL语句可以进行数值计算的 前提是 必须构建完整sql like模糊查询 模糊查询,使用通配符。掌握% _的使用。 %:零个及以上(任意个数的)的字符 _:一个字符 查询 雇员姓名中以'M'开头的雇员信息 select * from emp e where e.ename like 'M%'; 查询 雇员姓名中以'N'结尾的雇员信息 select * from emp e where e.ename like '%N'; 查询 雇员姓名中包含'M'的雇员信息 select * from emp e where e.ename like '%M%'; 查询 雇员姓名第二个字母为'M'的雇员信息 select * from emp e where e.ename like '_M%'; 查询 雇员姓名中倒数第二个字母为'E'的雇员信息 select * from emp e where e.ename like '%E_'; 查询中遇到内容中包含 % _ 使用escape('单个字符')指定转译符 escape : 逃离 逃脱 用法:添加标记位任意写一个字符,转译标记位身后的第一位 查询 姓名第二中包含 _ 雇员信息 select * from emp e where e.ename like '_a_%' escape('a'); 查询姓名第二位中包含 _ ,倒数第二位置包含%的 雇员信息 select * from emp e where e.ename like '_a_%a%_' escape('a'); in(xx,xx) 场景:查询部门编号为20和30的雇员信息 第一种写法: select * from emp e where e.deptno = 20 or e.deptno = 30; 第二种写法: select * from emp e where e.deptno in (20,30); 区分between..and 一个是取值一个是区间 场景:查询与SMITH在相同部门的雇员且薪水大于1500 select * from emp e where e.ename = 'SMITH' where e.sal > 1500; 思路 1.查询SMITH部门编号 select e.deptno from emp e where e.ename = 'SMITH'; 2.查询出部门编号为20的雇员信息 select * from emp e where e.deptno = 20 and e.sal >1500; 3.整合 --方法一{将第一次查询的语句 加()放进第二次的查询中} select * from emp e where e.deptno = (select e.deptno from emp e where e.ename = 'SMITH') and e.sal > 1500; 主查询-子查询--嵌套查询 SQL:执行顺序 (第一步:加载sql,第二步:编译(语义分析 先执行from 然后找 where 最后执行select)) 情景:查询与WARD、CLARK在相同部门雇员或者奖金为null select * from emp e where e.deptno in (select e.deptno from emp e where e.ename = 'WARD' or e.ename = 'CLARK') or e.comm is null; exists 表示存在的意思 exists()里面的代码相当于一个if语句 如果子查有查询结果就执行主查询 如果没查到就不执行主查询 一个执行主查询的限制条件 select * from emp where exists (select * from emp where ename = 'WARD'); order by排序 asc默认升序 情景:查询雇员信息并且按照职员编号显示 select * from emp order by empno; 情景:查询部门编号为30的雇员且按照薪资排序 select * from emp where deptno = 30 order by sal; desc降序排序 select * from emp where deptno = 30 order by sal desc; 情景:对部门编号为20或30的雇员,(工资+佣金)薪资进行升序排序,如果相同则按姓名降序 select e.ename, (nvl(e.sal, 0) * 12 + nvl(e.comm, 0)) s from emp e where e.deptno in (20, 30) order by s; 练习:查询EMP表显示获得补助的所有雇员名、工资及补助,并以工资升序和补助降序排序 select e.ename, e.sal s, e.comm c from emp e where e.comm is not null order by s asc, c desc; 情景:列出所有雇员的姓名及其上级的姓名(理解主查询和子查询) 1.查询出雇员 与 上级编号 select e.ename "雇员",e.mgr from emp e; 2.添加子查询 select e.ename "雇员", (select m.ename from emp m where m.empno = e.mgr) s from emp e; 小结:将emp拆分为两种表 雇员表和上级表,区分哪张表做哪件事情。 将e表的mgr编号给m表的empno,再通过empno返回出 m.ename 3.按照经理进行排序 将null放在排序前(默认 升序null放后面 降序null放前面) select e.ename "雇员", (select m.ename from emp m where m.empno = e.mgr) s from emp e order by s desc nulls first; 小结:需要将null放前 order by s desc nulls first 需要将null放后 order by s desc nulls last 添加信息: insert into emp(empno,ename,sal) values(1000,'t_%test',8989); insert into emp(empno,ename,sal) values(1200,'t_tes%t',8000); 函数分为系统内置函数、自定义函数,了解系统内置函数,了解掌握to_date、to_char(字符和日期的转换)。根据函数的返回结果,我们将函数分为单行函数和多行函数。 单行函数:一条记录返回一个结果。 多行函数:组函数、聚合函数:多条记录 返回一个结果。 日期函数 1.当前系统时间 sysdate/current_date 第一种写法 select sysdate "系统时间" from dual; 第二中写法 select current_date "系统时间" from dual; 2.修改日期 返回2天之后的时间 select sysdate , sysdate+2 from dual; 3.修改月份 返回5个月之后的时间 select add_months(sysdate,5) from dual; 雇佣日期2个月的时间 select ename, hiredate, add_months(hiredate,2) "2个月后" from emp; 4.月份之差 months_between(被减数,减数); 雇佣日期 举例现在的 月份数 select ename, moths_between(sysdate, hiredate) from emp; 5.最后一天 last_day(时间) 返回当前月份的最后一天 select ename, last_day(hiredate) d from emp; 6.下一个星期的时间 select next_day(sysdate,'星期二') from dual; --------------------------------------------------------------------- 转换函数 1.日期 --> 字符串 to_char() 2.字符串 -->日期 to_date() to_date(c,m) 字符串以指定格式转换为日期 to_char(d,m) 日期以指定格式转换为字符串 select to_date('2000.06.22','yyyy.mm.dd') from dual; 案例:查询受雇日期为1981/2/20的职员信息 1.to_date方法 将字符串转换为日期 select * from emp e where e.hiredate = to_date('1981/2/20','yyyy/mm/dd'); 2.to_char方法 将日期转换为字符串 select * from emp e where to_char(e.hiredate,'yyyy/mm/dd') = '1981/02/20'; 练习:查询82年的员工信息 1.使用模糊查询 select *from emp e where e.hiredate like '%82'; -性能不高 2.使用范围查询 1982.1.1-1982.12.31 select * from emp e where e.hiredate between to_date('1982-1-1', 'yyyy-mm-dd') and to_date('1982-12-31', 'yyyy-mm-dd'); 3.使用模糊查询的匹配法 select ename, to_char(hiredate,'yyyy')hiyer, to_char(hiredate,'mm') him from emp where to_char(hiredate,'yyyy') like '__82'; 3.大小写转换 4.截取 组函数 1.count:统计记录数 count() 2.max min 最大最小值 3.sum 4.avg count(参数 字段名) --统计任何列 都是一样的 select count (1) from emp; select count (2) from emp; select count (3) from emp; select count (*) from emp; 性能问题:通常来说:count (*) < count (1) 练习:列出最低薪金大于1500的各种工作及此从事此工作的全部雇员人数 select e.job, count(job) from emp e where e.sal > 1500 group by e.job ; max min:最大最小值 --统计员工中工资最低的 注意:将null返回,不参与运算 返回值1行 select max(sal),min(sal) from emp; sum 求和 --统计表中的总薪资 select sum(sal) from emp; avg 求平均值 --统计表中的薪资平均值 select avg(sal) from emp; 练习: 场景:统计ALLEN 所在部门的部门名称 以及 部门平均薪资 select d.dname "部门名称", (select avg(e.sal) from emp e where e.deptno = d.deptno) "平均工资" from dept d where d.deptno = (select e.deptno from emp e where e.ename = 'ALLEN'); 小结:单行函数与多行函数并列查询时 原则上是不能进行联合查询的 解决办法: 将单值转成多值 是可以的 但是将多值转换成单值是不可以的 将emp表放在子查询 就是单转多 将dept表放在子查询 就是多转单 也就是将主查询转换为多查询,子查询转换为单查询 --------------------------------------------------------------------- 分组group by 统计 每一个部门的平均工资 select vag(sal),min(sal),max(sal),sum(sal) from emp e group by e.deptno; 统计部门平均工资 大于 3000 select avg(sal) from emp e group by e.deptno; 分组的时候添加判断 having 过滤 having比select先执行 select avg(sal) from emp e group by e.deptno having (avg(sal) > 3000); 再排序 select 比 order by先执行 select avg(sal) s from emp e group by e.deptno having (avg(sal) > 3000) order by s; 情景:按部门 岗位 查询平均工资 select deptno, job ,avg(sal) from emp group by deptno,job order by emp.deptno; 情景:按部门 查询平均工资,且平均工资大于2000的部门编号 1.先分组 后过滤(不推荐) select * from (select deptno, avg(sal) avsal from emp where 1 = 1 group by deptno) where avsal > 2000; 2.过滤组,分组同时 过滤 select avg(sal), deptno from emp group by deptno having avg(sal) > 2000; 小结:having的出现就是解决 where group by的执行顺序,having是过滤组的,where是过滤行的 分组中不能包含非分组数据 select e.ename from emp e group by e.deptno; 这样是不能执行的 select avg(sal) from emp e group by e.deptno; 这样是可以执行的 情景:查询显示 高于本部门 平均薪资的职员姓名 岗位 薪水 部门编号,以部门编号升序排列 1. select e.ename, e.job, e.sal, e.deptno from emp e where e.sal > 平均薪资; 2. select e.ename, e.job, e.sal, e.deptno from emp e where e.sal > (select avg(sal) from emp d where e.deptno = d.deptno group by d.deptno); 3. select e.ename, e.job, e.sal, e.deptno from emp e where e.sal > (select avg(sal) from emp d where e.deptno = d.deptno group by d.deptno) order by e.deptno, e.sal desc; --------------------------------------------------------------------- 目前为止学到的关键词: select\from\where\group by\order by\having 执行顺序: from > where > group by > having > select > order by --------------------------------------------------------------------- Oracle多表查询是指基于两张表或者是两个视图以及以上的查询操作。在实际开发工作往往单表操作不能满足业务需求。 6.2.1等值连接 在笛卡尔积基础上,取条件列相同的值。 多表查询的笛卡尔积现象 联合查询 emp与dept select * from emp; 14行 select * from dept; 4行 select * from emp, dept ; 56行 - 14*4 上诉现象,多表查询中的 笛卡尔积现象(交叉乘) 解决:笛卡尔积现象联合查询需要 描述表之间的的关系-->主外键依赖(条件中描述) select * from emp, dept where emp.deptno = dept.deptno; 12行 情景:查询JAMES姓名、工作岗位、部门名称 select e.ename, e.job, d.dname from emp e, dept d where e.deptno = d.deptno and e.ename = 'JAMES'; 练习:显示'BLANK'的上级领导是谁 子查询 (嵌套): select d.ename "雇员", (select e.ename from emp e where e.empno = d.mgr) "上级" from emp d where d.ename = 'BLAKE'; 联合查询方式: select e.ename "雇员", m.ename "上级" from emp e, emp m where e.mgr = m.empno and e.ename = 'BLAKE'; 练习:显示WARD相同部门号的部门名、员工名、工资。按部门号升序,工资降序排列。 select e.ename, e.sal, d.dname from emp e, dept d where e.deptno = d.deptno and e.deptno = (select deptno from emp where ename = 'WARD') order by e.sal desc; 6.2.2非等值连接 select * from salgrade; select grade from salgrade where 900 > losal and 900 < hisal; select grade from salgrade where 900 between losal and hisal; 场景:查询员工姓名、工资及等级 select ename, grade, sal from salgrade s, emp e where sal between losal and hisal; 两种表的关联 关系不是通过主外键关联 而是范围关联(不需要掌握 使用少) 所谓自连接,是指在同一张表操作查询。是一种特殊的等值连接(数据源来源于同一张表) 注意:处理方式 使用多表处理,但是数据来自同一张表。--类似于查询SMITH的上级,使用的是同一张emp表。 分类: 1.单行子查询 2.多行子查询 场景:查询SMITH JONES所在部门名称 分析:这里SMITH JONED举例时没注意,他俩为同一个部门,假定SMITH和JONES所在的部门为2个部门,则我们需要显示的就是多行,先根据SMITH,JONES姓名查到他们的部门编号,再根据部门编号查到部门名称 select d.dname from dept d where d.deptno in (select e.deptno from emp e where e.ename in ('SMITH','JONES')); 拓展:当我们在from句子中使用子查询时,则该子查询就会当作一个视图来对待-内嵌视图,当在from子句中使用子查询时,必须给子查询指定别名。 select e.ename, e.deptno, e.sal, ds.mysal from emp e, (select deptno, avg(sal) s from emp group by deptno) as ds 内嵌视图:也就是一张临时表。因为要用到部门的平均工资和部门编号去和emp表中的部门编号关联,所以部门编号是有用的。 where e.deptno = ds.deptno; and e.sal > ds.s; --ds是标识 "平均工资"这是别名,用于显示,而不能代表这张表 外连接:主从表概念:完全显示的那张表为主表,从表为部分显示的表。如果从表中没有数据将会补null,从表中多余的数列将会省略(不显示)。 分为左外链接、右外连接、完全外连接。 6.5.1交叉连接 交叉链接返回左表中的所有行,左表中的每一行与右表中的所有行组合。交叉链接也称作笛卡尔积。 select * from emp cross join dept; --99式语法 select * from emp , dept; --92式语法 6.5.2 using连接 using 多连接中的关系(条件)链接 - 不常用 select e.ename, deptno, d.dname from emp e left join dept d using (deptno); 注意:using:局限性:主从表中,关联字段,必须字段名称相同。(在实际开发中,很多字段名逻辑是同一个,但是使用的字段名不同) on : 没有这种局限性,使用频率较高。 6.5.3 on连接(连接条件) select * from emp e left join dept d on (e.deptno = d.deptno); 6.5.1 92式语法 外连接(两张表 进行主外键关联) 区别自连接 情景:查询 职员的姓名 部门编号 部门名称。 select e.ename, e.deptno, d.dname from emp e , dept d where e.deptno = d.deptno; --12条数据 2条没有部门信息的数据没有显示 学生表-成绩表-(部分学生缺考)--如果使用以上的查询方式 缺考的学生没有成绩那么他的学生信息也不会显示 处理以上情况(其中一张表中没有记录,也要照常显示): (+) select e.ename, e.deptno, d.dname from emp e , dept d where e.deptno = d.deptno(+); --14条数据 以emp为主表,dept为从表 select e.ename, e.deptno, d.dname from emp e , dept d where e.deptno(+) = d.deptno; --7行数据 以deot为主表,emp为从表。 小结: 92式: (+)放左边:左链接:完全显示左边表的数据。 "+"添加至右边表,将右边设置为从表,配合左边主表显示。 (+)放右边:右链接:完全显示右边表的数据。 "+"添加至左边表,将左边设置为从表,配合右边主表显示。 反正就是放哪儿哪儿是从表,放哪儿哪儿补充null。 6.5.2 99式语法 99式语法:(left right):简单 明了 左外连接 select * from emp e left join dept d on (e.deptno = d.deptno);14行 右外连接 select * from emp e right join dept d on (e.deptno = d.deptno);13行 联系:小于20部门编号的员工的部门名称 select d.dname from emp e left join dept d on e.deptno = d.deptno and e.deptno < 20; 14条 select d.dname from emp e,dept d where e.deptno = d.deptno(+) and e.deptno < 20; 3条 小结: 92式(+)修饰的为从表 99式left/right join on修饰的为主表。 6.6练习 1.列出最低薪金大于1500的各种工作及此从事此工作的全部雇员人数 内嵌视图:select e.job s, count(job) from emp e group by e.job having min(e.sal) > 1500; select count(1), d.job from emp d right join (select e.job s from emp e group by e.job having min(e.sal) > 1500) ds on (d.job = ds.s) group by d.job; 下面这条代码是错误的,应该先分组在过滤,题目需求排除最低工资小于1500的部门 ,需要排除的是部门,而e.sal>1500排除的仅是工资,所以执行出来的记录会多出一条SALSMAN部门工资=1600的数据 select e.job, count(job) from emp e where e.sal > 1500 group by e.job; 2.列出在每个部门工作的员工数量、平均工资 select d.dname, avg(e.sal), count(dname) from emp e right join dept d on (e.deptno = d.deptno) group by d.dname; group by xxx 怎么与前面select匹配 --select deptno, count(deptno), avg(sal) from emp group by deptno; 3.查出某个员工的上级主管,并要求出这些主管中的薪水超过3000 --自连接 emp select e.ename "员工", m.ename "上级", m.sal "上级工资" from emp e left join emp m on (e.mgr = m.empno) where m.sal > 3000; --显示员工和上级 --92式: select e.ename "员工", m.ename "上级" from emp e ,emp m where e.mgr = m.empno; --99式: select e.ename "员工", m.ename "上级" from emp e left join emp m on e.mgr = m.empno; --去重之后的 select distinct m.ename "上级", m.sal "上级工资" from emp e ,emp m where e.mgr = m.empno and m.sal > 3000; 4.求出部门名称中,带'S'字符的部门员工的工资总和 、部门人数 --分析:数据来自emp和dept表,带s字符来自dept表,工资总和和部门人数来自 emp表。 -- 按照部门进行分类 select d.dname, sum(e.sal) s, count(1) from dept d right join emp e on (d.deptno = e.deptno) where d.dname like '%S%' group by d.dname order by s desc; --步骤: select d.dname from dept d where d.dname like '%S%' group by d.dname; select d.dname from dept d,emp e where d.deptno = e.deptno and d.dname like '%S%' group by d.dname; --关联之后就没有OPERATIONS这个部门了 select d.dname, sum(e.sal), count(d.dname) from dept d,emp e where d.deptno = e.deptno and d.dname like '%S%' group by d.dname; 数据分页,根据 Oracle 数据库存储大量的数据,但是实际业务中有很多只需要部分数据,因此,促使着要做数据分。 7.1.1 --分页技术 解决大规模数据 分批展示 oralce 分页比较特殊 select * from emp; --14条数据 场景:只需要展示 5-10 条数据 Oracle分页需要借助 伪列(rownum) 进行分页(oracle本身没有分页) select e.*, rownum rid from emp e; select e.* rownum rid from emp e where rid between 5 and 10;--这样是不行的:where先执行where执行时还没有rid 正确方式: --1.嵌套: 1. select * from (select e.* , rownum rid from emp e) ds where ds.rid between 5 and 10; 2. select * from emp e left join (select empno, rownum red from emp) ds on (e.empno = ds.empno) where ds.red > 4 and ds.red < 11; --99式 优化: select * from emp e left join (select empno, rownum red from emp) ds on (e.empno = ds.empno) where ds.red < 11 and ds.red > 4; --这样可以先把rid锁定在rid-11以前 可以加快搜索速度 3. select * from emp e, (select empno, rownum red from emp) ds where (e.empno = ds.empno(+)) and ds.red > 4 and ds.red < 11; --92式 7.1.2函数分页 --2.分页函数: select * from (select e.*, row_number() over(order by e.sal) as num from emp e) ds where num between 5 and 10; 小结:oralce中分页查询 -- 记录数 从页面的上页数 到 -- 记录数(这个中间是需要转换的--java) 所以需要在java代码中封装 分业实现类 面试题:如果判断sql语句的优劣性? --1.sql的执行时间(越短越好) --2.sql执行的CPU占有率(越小越好) --3.sql可读性 合并查询(非重点) 在实际卡开发工作中会涉及到多个select语句进行合并,这时候就需要引用集合操作符号(union、union all、intersect、minus) 集合运算:并集、交集、差 A = {1,2,4} B = {2,4,5} A u B = {1,2,4,5} A - B = {1} B - A = {5} 1. union 联合-该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中重复行。 --查询列必须相同 不然会报错 场景:查询薪水大于2500 或 职位是经理的雇员的职业姓名、薪水和职位。 select ename, sal, job from emp where sal > 2500 union select ename, sal, job from emp where job = 'MANAGER'; union all 没有去重 select ename, sal, job from emp where sal > 2500 union all select ename, sal, job from emp where job = 'MANAGER'; 2. intersect 集合-使用该操作符用于取得两个结果集的交集。 场景:查询薪水大于2500 且 职位是经理的雇员的职业姓名、薪水和职位。 select ename, sal, job from emp where sal > 2500 intersect select ename, sal, job from emp where job = 'MANAGER'; 3. minus 差-使用该操作符用于取得两个结果集的差集,它只会显示存在第一个集合中,而不存在第二个集合中的数据。 场景:查询薪水大于2500 但是职位不是 经理的雇员的职业姓名、薪水和职位。 select ename, sal, job from emp where sal > 2500 minus select ename, sal, job from emp where job = 'MANAGER'; --面试可能遇见问题: 1.合并查询中用到了哪些关键字,并且解释union和union all的区别。 7.3数据库的DML操作 表中的数据实现管理{ c r u d } c:create r:read u:update d:delete --1.insert插入数据库 格式:insert into tabel [(column [,column...])] values(values [,value...]); 增加 emp表中 sxt 职员编号 1521 薪资 2.13 insert into emp e(e.empno, e.ename, e.sal) values (1521, 'sxt', 2.13); select * from emp where empno = 1521; --注意:当insert执行后,插入的数据暂时缓存在一个临时的视图中,所以接下来的语句中能查询到 -- 在没有提交的时候,emp表中还没有这个数据,在别的窗口视图中查询不到这个数据 -- 所以插入后需要提交。 练习:随便插入几条数据 insert into emp e(e.empno, e.ename, e.sal) values (1005, 'ddnn', 300); insert into emp e(e.empno, e.ename, e.sal) values (0811, 'JJLL', 5000); select * from emp ; --注意: 插入的数据应与字段的数据类型相同 数据的大小应在列的规定范围内,例如:不能将一个长度为80的字符串加入到长度40的列中。 在valuse中列出的数据位置必须与被加入的列的排列位置相对应。 字符和日期型数据应包含在单引号中。 --2.update更新操作 格式:update tbl_name set col_name = exp(...) where _definition; 语法: update 表名 set 字段名 = 值 ... where xxxx 示例:update emp set empno = '1983' where empno = 0811; 练习:随意更改几条信息 update emp set ename = 'ywj' where empno = 1983; update emp set ename = 'dnn', empno = '0825' where empno = 1005; --3.delete删除操作 格式:delete from tbname where_definition; 示例:按条件删除 delete from dept where deptno = 50; delete from emp where empno = 1521; 重点注意:实际开发中,不管是删除表还是表中记录,都慎重。 实际中对记录的删除,都采用逻辑删除,不是物理删除。 逻辑删除:额外添加一个字段,表示是否删除(0未删除 1删除) --实际删除中有个类似于 isDelete的字段(0表示未删除,1表示删除) --当我们需要删除的时候,如下:将表示删除的字段的值改成1 --update emp set idDelete = 1 where id = 17; 物理删除: 直接delete,实际中千万不能直接delete 7.4开发中的读写 开发中的 数据库“读“”写“ “读”:select -->并不会改变数据-不需要提交 “写”:insert update delete -->直接更改数-需要事物提交 “读”“写”分离: 实际中,“读”操作的使用频率远远超过“写”,“写”的时候可能会出现问题 所以将原本的一个数据库,分割成2个数据库,其中一个数据库负责“读”,一个负责“写” --这就是数据的读写分离 提升系统的容灾性。 所以一般“读”的数据库会有很多个出现一个集群,而“写”往往只有一个数据库。 “读”“写”数据同步问题: 数据库中是多线程操作的 一个是SQL线程(更新SQL操作),一个是IO线程(记录操作日志,可以实行数据恢复),通过远程通信,完成数据同步。 比如插入数据时,在写的数据库插入时,会立马执行IO线程, 而读的线程中有一个检测io的心跳检测(一个远程通信),每100毫秒检测一次,用这样的方式实现数据同步 当有一天读数据库中的某个数据被删了时,可以通过IO线程记录的操作日志恢复。 1.4使用客户端链接数据库PLSQL
二、关系数据库(database manager system)
三、DML语言:数据库管理语言
3.1Oracle基本操作
3.2用户管理
第二章 Oracle数据库
一、表(Tabel)
1.1理解表
1.2表结构
二、Scott用户表
2.1查看用户表
2.2查看表结构
三、数据库设计原则——三范式
四、SELECT
4.1查询语法
4.2查询列
4.3查询知识点
五、Oracle函数
5.1单行函数
5.2组函数
六、多表查询
6.1Oracle多表查询操作
6.2多表查询的笛卡尔积现象
6.3自连接
6.4子查询
6.5外连接
七、Oracle技术与符合查询
7.1分页技术
7.2合并查询
7.3数据库的DML操作(CRUD)