Oracle 数据库系统是美国 Oracle 公司(甲骨文)提供的以分布式数据库为核心的一组软件产品,是目前世 界上使用广泛的关系数据库管理系统。
Oracle 数据库是数据的 物理存储文件 。这就包括 Oracle 中所有的文件类型:数据文件 ORA 或者 DBF、控 制文件 CTL、联机日志、参数文件。Oracle 数据库的概念和其它数据库不一样,** 一个 Oracle 系统只有一个数据库。 **
一个 Oracle 实例由一系列的后台进程和内存结构组成 。一个数据库可以有 n 个实例,通常我们也只创建一个实例。 实例与数据库的关系就像对象与类的关系 。
![image-20221014104823187](Oracle 基础.assets/image-20221014104823187.png)
从实例和数据库的概念上来看:实例暂时的,它不过是一组逻辑划分的内存结构和进程结构,它会随着数据库的关闭而消失。数据库它其实就是一堆物理文件(控制文件,数据文件,日志文件等等),它是永久存在的。
MySQL 与 Oracle 数据库之间最大的区别要属 表空间 。 在 MySQL 中一个项目对应一个数据库,而在 Oracle 中通常 一个项目对应一个用户。
Oracle 数据库的逻辑结构: 被划分成一个或多个表空间,而一个表空间则对应着一个或多个物理的数据库文件。 每个数据库至少有一个 SYSTEM 表空间和 USER 表空间,这是系统安装完后自动创建的。
创建表空间的语法
删除表空间的语法
![image-20221014112154788](Oracle 基础.assets/image-20221014112154788.png)
12345
-- 创建表空间 space1,数据文件为 space1.dbf,初始大小为 20M,空间不足自动扩展。create tablespace space1 datafile 'space1.dbf' size 20m autoextend on;-- 创建表空间 space2,数据文件为 space2.dbf,初始大小为 500kcreate tablespace space2 datafile 'space2.dbf' size 500k;
![image-20221014112357305](Oracle 基础.assets/image-20221014112357305.png)
![image-20221014112713120](Oracle 基础.assets/image-20221014112713120.png)
12
-- 删除 space2 表空间,同时删除内容和文件drop tablespace space2 including contents and datafiles;
创建用户的语法
给用户权限
![image-20221014113135580](Oracle 基础.assets/image-20221014113135580.png)
-- 创建用户 user1,密码 orcl,指定默认表空间为 space1create user user1 identified by orcl default tablespace space1;
![image-20221014124548916](Oracle 基础.assets/image-20221014124548916.png)
创建好用户以后,使用 user1 登录,出现如下提示:
用户没有相应的权限,接下来要给用户添加权限。
角色:将多种操作权限做为一个权限集合保存下来,并且起一个名字。
![image-20221014134733339](Oracle 基础.assets/image-20221014134733339.png) 2) resource
![image-20221014134745465](Oracle 基础.assets/image-20221014134745465.png) 3. dba
DBA 角色:拥有全部特权,是系统最高权限,只有 DBA 才可以创建数据库结构,并且系统权限也需要 DBA 授出,且 DBA 用户可以操作全体用户的任意基表,包括删除。如:system
![image-20221014135131156](Oracle 基础.assets/image-20221014135131156.png)
-- 进入 system 用户下给用户 user1 赋予 dba 权限grant dba to user1;
创建和删除表结构
![image-20221014135449605](Oracle 基础.assets/image-20221014135449605.png)
![image-20221014135637733](Oracle 基础.assets/image-20221014135637733.png)
![image-20221014135715844](Oracle 基础.assets/image-20221014135715844.png)
123456789101112131415161718
/* 以 user1 登录,创建 person 表,字段 pid 是 number(10)主键,name 字符串 20,非空,性别字符串长 2,性别添加检查约束,只能输入男或女,生日是日期类型 */create table person (pid number(10) primary key,name varchar2(20) not null,sex varchar2(20) check(sex='男' or sex='女'),birthday date);select * from person;-- 插入 1 条正确的数据insert into person values (1, '悟空','男',to_date('2000-11-11','yyyy-mm-dd'));-- 在 Oracle 中默认事务是手动提交commit;-- 插入 1 条错误的数据,性别为'妖'insert into person values (2, '白骨精','妖',to_date('2000-11-11','yyyy-mm-dd'));
![image-20221014142644878](Oracle 基础.assets/image-20221014142644878.png)
-- 删除全部数据truncate table person;-- 同时删除表结构和数据drop table person;
修改表的结构
![image-20221014143050520](Oracle 基础.assets/image-20221014143050520.png)
12345678
-- 在 person 表中 address 增加列,类型为 varchar2(100)alter table person add address varchar2(100);-- 把 person 表的 address 列的长度修改成 50 长度alter table person modify address varchar2(50);-- 把 person 表字段 address 字段名称修改为 homealter table person rename column address to home;
添加列:add 修改类型:modify 改名:rename column .. to
插入记录,序列的使用
![image-20221014145544589](Oracle 基础.assets/image-20221014145544589.png)
123456789101112131415
-- 插入部分列:pid 是 1,名字是孙悟空insert into person (pid,name) values(1,'孙悟空');-- 插入所有列:pid 是 2,名字猪八戒,男,生日要使用 to_date('日期','yyyy-mm-dd')进行类型转换insert into person values (2,'猪八戒','男',to_date('1999-02-11','yyyy-mm-dd'),'高老庄');-- 查看代码select * from person;-- 提交事务commit;-- 回滚事务rollback;
如果事务没有默认提交,可以使用commit提交事务,rollback回滚事务。本次用的docker oracle12c的镜像版本。默认开启了事务。
默认的情况下,Oracle 没有主键的自增长。使用序列来解决这个问题。 什么是序列:一串连续的整数数字 序列的作用:在 Oracle 中主要做为主键的自增长功能。
![image-20221014151116102](Oracle 基础.assets/image-20221014151116102.png)
1234567891011
-- 创建一个序列名为 seq_one,起始值为 1,步长为 2,最大值 9,循环使用,不指定缓存create sequence seq_one start with 1increment by 2maxvalue 9cyclenocache;-- 查询用户USER1的所有序列select SEQUENCE_OWNER,SEQUENCE_NAME from dba_sequences where sequence_owner='USER1';
在序列中提供了以下的两种操作:
![image-20221014151411849](Oracle 基础.assets/image-20221014151411849.png)
-- 查询当前的序列号select seq_one.nextval from dual;select seq_one.currval from dual;-- mysql 查询现在的时间select now();-- 在 oracle 中使用 sysdate 查询现在的时间-- 注:oracle 中只要使用 select 语句,语法必须包含 from -- 在 oracle 中有一个虚拟表名:dual,为了让 select 语法完整select sysdate from dual;-- 删除对应的序列DROP SEQUENCE seq_one;
总结 :dual 是什么? 是虚拟表,用来让 select 的语法完整;
在实际项目中每一张表会配一个序列,但是表和序列是没有必然的联系的,一个序列被哪一张表使用都可以, 但是我们一般都是一张表用一个序列。
-- 示例:使用序列插入自动增长的主键,插入记录"白骨精",性别:女,生日,地址为广州select * from person;-- 创建序列create sequence seq_person start with 3;-- 插入数据insert into person values(seq_person.nextval, '白骨精','女',sysdate,'广州');
对表中的记录进行更新和删除
![image-20221014161859638](Oracle 基础.assets/image-20221014161859638.png)
-- 将所有人的地址改成天河区update person set home='天河区';-- 将 pid 为 2 的记录,改成地址改成深圳update person set home='深圳' where pid=2;
![image-20221014162521877](Oracle 基础.assets/image-20221014162521877.png)
-- 删除 pid 为 1 的记录delete from person where pid=1;
使用字符函数
使用数值函数
使用 scott 用户登录,这是系统默认的一个普通用户,密码默认是 tiger,这个用户下已经创建了一些表可以使用。
![image-20221014174010459](Oracle 基础.assets/image-20221014174010459.png)
-- 查看用户列表select username from dba_users;-- 修改 scott 的密码alter user scott identified by mima;-- 修改被锁定账户状态alter user scott account unlock;
点击ER图表,即可展示表与表之间的关系
![image-20221014184131666](Oracle 基础.assets/image-20221014184131666.png)
123456789101112
-- 查询系统现在的日期select sysdate from dual;-- 查询姓名,计算员工进入公司的天数(今天-入职日期),再取整select * from emp;select ename, round(sysdate-hiredate) as 天 from emp;-- 查询姓名,计算员工进入公司的周数(sysdate – 入职日期)/7 就是周数,再取整数值select ename, round((sysdate-hiredate)/7) as 周 from emp;-- 查询姓名,计算员工进入公司的月数,再取整select ename, round(months_between(sysdate,hiredate)) as 月 from emp;
123456789
-- 查询员工编号,姓名,入职日期,日期格式使用'年-月-日'的格式显示select empno,ename,to_char(hiredate,'yyyy-mm-dd') from emp;-- 查询员工编号,姓名,入职日期,拆分成三个列:年,月,日select empno,ename,to_char(hiredate,'yyyy') 年,to_char(hiredate,'mm') 月,to_char(hiredate,'dd') 日 from emp;-- 查询员工编号,姓名,入职日期,格式:yyyy"年"mm"月"dd"日"select empno,ename,to_char(hiredate,'yyyy"年"mm"月"dd"日"') 入职日期 from emp;
学习空值函数,多条件判断函数和多条件判断语句
![image-20221019151853963](Oracle 基础.assets/image-20221019151853963.png)
⚫ 需求:查询所有的雇员的姓名和年薪,年薪=月薪*12+奖金
我们发现很多员工的年薪是空的,原因是很多员工的奖金是 null,null 和任何数值计算都是 null,这时我们可以使用 nvl 来处理。类似于 mysql 中的 ifnull 函数
123456
-- 查询所有的雇员的姓名和年薪,年薪=月薪*12+奖金select ename, sal, comm from emp;select ename,sal * 12 + comm 年薪 from emp;-- 如果为 null,则设置为 0select ename,sal * 12 + nvl(comm,0) 年薪 from emp;
![image-20221019154235491](Oracle 基础.assets/image-20221019154235491.png)
1234567891011121314151617
/* 使用 case-when-end 查询出所有雇员的名字和职位中文名:CLERK 业务员,SALESMAN 销售,PRESIDENT 总裁,ANALYST 分析师,MANAGER 经理,否则是其他 */SELECT ename,CASE job WHEN 'CLERK' THEN '业务员' WHEN 'SALESMAN' THEN '销售' WHEN 'ANALYST' THEN '分析师' WHEN 'MANAGER' THEN '经理' ELSE '其他' END 职位 FROM emp;
![image-20221019154841550](Oracle 基础.assets/image-20221019154841550.png)
![image-20221019160459139](Oracle 基础.assets/image-20221019160459139.png)
-- 所有员工人数select count(*) 人数 from emp;-- 查询出来员工最低工资select min(sal) 最低工资 from emp;-- 查询出员工的最高工资select max(sal) 最高工资 from emp;-- 查询出员工的平均工资select round(avg(sal),2) 平均工资 from emp;-- 查询出 20 号部门的员工的工资总和select sum(sal) from emp where deptno=20;-- 查询empselect * from emp;
![image-20221019164735160](Oracle 基础.assets/image-20221019164735160.png)
-- 查询出每个部门 ID 和平均工资,并且保留 2 位小数select deptno 部门, round(avg(sal),2) 平均工资 from emp group by deptno;-- 查询每个部门的人数select deptno 部门, count(*) 人数 from emp group by deptno;
⚫ 疑问:部门编号,每个部门的人数。能否在上面再加 1 列员工姓名
1
在 oracle 中会出现错误: ORA-00979: not a GROUP BY expression
分组与 MySQL 的区别:
mysql 中可以,会显示每组中第 1 个员工
⚫ select 后面只能出现:group by 后面列或聚合函数
123
-- 查询出部门平均工资大于 2000 的部门。先分组查询每个部门的平均工资,再过滤select deptno 部门, round(avg(sal),2) 平均工资 from emp group by deptno having avg(sal)>2000;
学习笛卡尔积,隐式内连接,显示内连接查询
select * from emp,dept;
在两张表中我们发现有一个共同的字段是 depno,depno 就是两张表的关联的字段,我们可以使用这个字段来做限制条件,两张表的关联查询字段一般是其中一张表的主键,另一张表的外键。
子查询返回单行单列数据
-- 查询比 SCOTT 工资高的员工select * from emp where sal > (select sal from emp where ename='SCOTT')
子查询返回单行多列数据
-- 查询出和 SCOTT 同部门同职位的员工,并且不显示 SCOTT 本人select * from emp where deptno = (select deptno from emp where ename='SCOTT')and job = (select job from emp where ename='SCOTT') and ename<>'SCOTT';-- 优化代码select * from emp where (deptno,job) = (select deptno,job from emp where ename='SCOTT') and ename<>'SCOTT';
子查询返回多行多列数据
1234
-- 查询每个部门最低工资的:员工姓名,部门名,工资-- 1.表连接查询部门表和员工表,查询列:部门编号,部门名,每个部门的最低工资值。按部门编号和部门名称分组,得到多行多列的虚拟表。最小工资定义别名 minsalselect d.deptno,d.dname, min(sal) minsal from emp e inner join dept d on e.deptno = d.deptno group by d.deptno,d.dname;
-- 2.表连接查询虚拟表和员工表:查询员工名,部门名,工资。表连接条件是部门编号相等,而且工资等于最小工资select e.ename 员工名, t.dname 部门名, e.sal 工资 from emp e inner join (select d.deptno,d.dname, min(sal) msal from emp e inner join dept d on e.deptno = d.deptno group by d.deptno,d.dname) ton e.deptno = t.deptno and e.sal = t.msal;
学习 Oracle 中分页查询
ROWNUM 是 Oracle 数据库从数据文件中读取数据的顺序。它取得第一条记录则 ROWNUM 值为1,第二条为 2,依次类推。如果你用>, >=, =, between…and 这些条件,因为从表中得到的第一条记录的 ROWNUM 为 1,不满足 ROWNUM>5 的条件则被过滤。接着取下条,它的 ROWNUM 还是 1,又被过滤,依次类推便没有了数据。
解决方案:需要使用子查询将 rownum 以虚拟表的形式保存下来,再进行二次查询。
-- 分页查询每页显示 5 条-- 查询empselect * from emp;-- 伪列 rownumselect rownum, e.* from emp e;-- 查询第 1 页select rownum, e.* from emp e where rownum > 0 and rownum<=5;-- 查询第 2 页(查询不到数据,因为从表中得到的第一条记录的 ROWNUM 为 1,不满足 ROWNUM>5 的条件则被过滤。接着取下条,它的 ROWNUM 还是 1,又被过滤,依次类推便没有了数据)select rownum, e.* from emp e where rownum > 5;-- rownum 是对结果集进行编号-- 将 rownum 做成一张虚拟表,再次查询select t.* from (select rownum rn, e.* from emp e) t where rn>0 and rn<=5;select t.* from (select rownum rn, e.* from emp e) t where rn>5 and rn<=10;select t.* from (select rownum rn, e.* from emp e) t where rn>10 and rn<=15;
分页中要使用伪列:rownum 代表的是查询结果编号,使用子查询来实现表分页
a) 数据库 b) 实例 c) 表空间 d) 物理文件
a) create tablespace … datafile … size… autoextend on b) drop tablespace … including contents and datafiles c) create user… identified by… default tablespace d) grant 角色 to 用户名
a) create sequnece b) start with c) increment by d) maxvalue e) cycle f) nocache
![image-20221020104310805](Oracle 基础.assets/image-20221020104310805.png)
a) max,min,count,avg,sum
a) select from where group by having
a) 内连接:inner join … on b) 左连接:left join … on c) 右连接:right join … on d) 全连接:full join … on
a) 单行单列 b) 单行多列 c) 多行多列