--DDL:数据库定义语言
--描述主要的数据库对象
--创建表
--描述各种数据类型
--修改表的定义
--删除 ,重命名和清空表
--常见的对象
--表 基本的数据存储集合由行和列组成
--视图 从表中抽离出的逻辑上相关的数据集合
--序列 提供有规律的数据(一般用作主键的值 )
--索引 提高查询效率
--同义词 给对象起别名
--命名规则
--表名和列名
--必须以字母开头
--必须在1-30个字母之间
--只有由A-Z,a-z,0-9 ,_,$,#组成
--必须不能是oracle的保留字
--必须不能和用户定义的其他对象重名
--创建表的方式
--第一种方式( 白手起家式 )
--第二种方式 ( 依托于某个已经存在的表 )
create table emp_sc1807_2
as
select id,name,salary from emp ;--得到全部的数据 和选定的字段
create table emp_sc1807_2_01
as
select id,name,salary from emp where id>20;--得到id 大于20的数据
create table emp_sc1807_2_02
as
select id,name,salary from emp where 1=2;--得到数据为空 , 用逻辑判断
--数据类型
-- varchar 2( size) 可变长的字符数据 最大可达到4KB
--char( size) 定长字符数据 最大可达到2KB
--number( size) 可变长的数值数据 最多可以存储精度达到38 位数据
--DATE 日期型数据
--long 可变长的字符数据 ( 最大可达到4 G)
--CLOB 定长的字符数据( 最大可达到 4 G)
--BLOB 存储最大可达到 4G,主要用于存储视频图片 ,以二进制形式进行存储 .
--修改表的定义
--使用 alter table 语句
--1. 追加新的列
select *from emp_sc1807_2;
alter table emp_sc1807_2 add(age number(10));--增加一列
update emp_sc1807_2 set age =null where id =1;---增加数据
--修改失败 如果要修改列的属性,那么该列必须为空
alter table emp_sc1807_2 modify(age varchar2(10));
--为新追加的列定义默认值
alter table emp_sc1807_2
modify(age varchar2(10) default 100);
--删除一个列
alter table emp_sc1807_2 drop column age ;
--数据定义语言是自动提交的
--重命名一个列名
alter table emp_sc1807_2 rename column name to names;
--删除表
drop table emp_sc1807_2_01
--清空表数据
delete emp_sc1807_2; --不是真正的定义语言 可以回滚 ,不是自动提交的
truncate table emp_sc1807_2; --不可以回滚 , 自动提交
--回滚
rollback;
--数据库定义语言DDL:回滚语句无效,相当于自动提交
--ps: trancate 从硬盘上删除表中所有数据,释放硬盘
--练习 :
--1. 将表 emp 的数据插入到新表的 emp2 中,要求完全复制
--2. 将表 emp中 ename 列长度增加到50
--3. 将表命名为employee
--4.在表emp中增加新的列test_column
--5.在表employee中将test_column设置为不可用 ,然后删掉
--6. 删掉不可用的列
select * from emp2;
--1
create table emp2
as select * from emp;
--2
alter table emp modify(name varchar2(50));
--3
alter table emp rename to employees;
--4
alter table employees add(test_column number(10));
--5
ALTER TABLE employees SET UNUSED (test_column)
--6
ALTER TABLE employees DROP UNUSED COLUMNS;
-- 数据处理语言DML
--delete: 清空表数据 可回滚
--约束
-- 什么叫约束: 约束是表级的强制规定
-- 主要的约束有以下5 种
--not null
--unique
--primary key
--foreign key
--check
--ps: 如果不指定约束名,那么oracle_server 自动按照
--SYS_CN 的格式指定约束名 .
--创建和修改约束
--建表的同时
--建表之后
--可以在 表级或列级定义约束
--ps: 可以通过数据字典视图查看约束
--表级约束和列级约束
--作用范围
--1.列级约束只能作用在一个列上
--2. 表级约束可以作用在多个列上( 当然表级约束也可以作用在一个列上 )
--定义方式
--1. 列级约束必须跟在列的定义 ,表约束不与列一起而是独定义
--ps: not null : 该约束只能定义在列上 .
create table emp_sicheng(
id number(3) constraint emp_sicheng_01_id_nn not null,
name varchar2(20) not null,
salary number(10,2)
);
create table emp_sicheng_01(
id number(3) constraint emp_sicheng_01_id_uk unique,
name varchar2(20) not null,
salary number(10,2)
);
create table emp_sicheng_02(
id number(3) ,
name varchar2(20) ,
salary number(10,2),
--添加表级约束
constraint emp_sicheng_02 unique(id,name)
);
insert into emp_sicheng_02 values (2,null,1000);
select * from emp_sicheng_02;
-- 表级约束无法在建表后添加
--如果要添加 ,只能列级的方式
--ps: 唯一约束对空值无效
--ps: 主键的 约束是非空且唯一.
--外键
create table emp_sicheng_05(
id number(10),
name varchar2(20),
salary number(10,2),
department_id number(10),
-- 表级约束
constraint emp_sicheng_05_uk unique(name),
constraint emp_sicheng_05_pk primary key(id),
constraint emp_sicheng_05_fk foreign key(department_id)
references departments(department_id)--关联departments 表中的 id ( 主键 )
);
--check( 只能是列级约束 )
create table emp_sicheng_06(
id number(10),
name varchar2(20) constraint emp_sicheng_name_nn not null,
salary number(10,2) check(salary>15000 and salary<20000),
--表级约束
constraint emp_sicheng_id_pk primary key(id)
);
insert into emp_sicheng_06 values(1,'三儿',16000);
select * from emp_sicheng_06;
-- 解决方案( foreign key )
--1. 先删除字表中的记录,在删除父表中的记录
--2. 使用级联删除 .
-- 小结 :
--1. 如何在建表的同时添加列级约束和表级约束
--2. 非空约束只能是列级约束并且唯一约束对空值 (null) 无效
--3. 表级约束只能在建表的同时添加
--4. 外键约束 : on delete cascade ( 级联删除 ):
--当父表中的列被删除时子表中对应的列也被删除
-- on delete set null ( 级联置空 )
--当父表中的列被置空时子表中响应的列置空 .
-- 子表在插入操作时 , 关联字段的值必须是父表已经存在的值
-- 父表在执行删除时 , 必须要先将子表中关联字段对应的值删除才能成功 .
-- 建表之后添加约束 使用 alter table 语句
-- 添加或删除约束 , 但是不能修改
-- 有效化约束 和无效化约束
--ps: 添加 not null 约束必须要使用 modify 语句 .
--建表之后添加非空约束
alter table emp_sicheng_06 modify(id number(2) not null);
--建表之后删除非空约束
alter table emp_sicheng_06 drop constraint emp_sicheng_name_nn ;
----建表之后添加唯一约束
alter table emp_sicheng_06 add constraint emp_sicheng_name_uk unique(name) ;
-- ps: 有值的情况下添加不一定成功 .
-- 约束无效化
-- 在 alter table 语句中调用disable 使用子句将约束无效化但不会删除约束
alter table emp_sicheng_06 disable constraint emp_sicheng_name_uk ;
--添加两个说明 约束无效化了
insert into emp_sicheng_06 values(3,'as',16000);
select * from emp_sicheng_06;
--约束有效化
alter table emp_sicheng_06 enable constraint emp_sicheng_name_uk
--ps: 如果表中已经存在了相同的值 ,则该语句无法执行 .
-- 课后练习
-- 表 employee
--1. 创建这种表 , 并输入相关数据
--2 . 查询员工的 first_name,department_id,salary,其中员工的 department_id,salary 与
--有奖金的任何一位员工的,department_id ,salary 相同即可 .
--3. 选择工资大于 job_id=''23' 的员工工资的员工的 first_name和 job_id 以及salary
select * from employee;
create table employee(
employee_id number(3),
first_name varchar2(20),
job_id number(3),
manage_id number(3),
department_id number(4),
hire_date varchar2(40),
salary number(10,2),
commission number(1)
);
insert into employee values(499,'wancl8',28,114,1018,'2018/10/10',1081,1);
insert into employee values(10,'秀儿2',21,109,1018,'2017/11/17',1020,0.1);
select a.first_name, a.job_id,a.salary from employee a where salary>all(
select s.salary from employee s where job_id=23);
--all 和 any
--all: 表示和返回的所有值比较
--any: 表示和返回的任意一个值比较
select first_name,department_id,salary from employee
where (department_id,salary) in
(select department_id,salary from employee
where commission is not null)
-- 笛卡尔积
select first_name,department_id,salary from employee
where department_id in
(select department_id from employee
where commission is not null)
and
salary in
(select salary from employee
where commission is not null);
select * from employee;
--1.选择所有没有管理者的员工的 first_name( 使用 not exists)
select first_name from employee where manage_id is null;
--not exists
--配合子查询使用 , 当子查询返回的结果为空 ,表示where条件成立,执行外查询
--exists : 和上面相反
select first_name from employee e1 where
not exists(
select 'C' from employee e2 where employee_id = manage_id
)
--2.查询与7369 号或7499
--manage_id 或department_id 相同的其他员工的
--employee_id,manager_id,department_id
select manage_id,department_id,department_id from employee
where manage_id in
(select manage_id from employee where employee_id in(499,369))
or department_id in
(select department_id from employee where employee_id in(499,369))
--3.查询与7369号或7499 号员工的
--manage_id和department_id相同的其他员工的
--employee_id,manager_id,department_id
select employee_id,manage_id,department_id from employee
where(manage_id,department_id) in
(select manage_id,department_id from employee where employee_id in(1,3))
and employee_id not in (1,3)
--4. 返回比本部门平均工资高的员工的 first_name,department_id,salary,以及平均工资
--第一步: 计算每个部门的平均工资
select avg(salary) from employee group by department_id;
--第二部 :筛选出比这个平均工资高的员工
select first_name,e1.department_id,salary,e2.sal from employee e1 ,
( select department_id, avg(salary) sal from employee group by department_id) e2
where e1.department_id = e2.department_id
and e1.salary>e2.sal;
--单列子查询
--单列子查询表达式是在一行中只返回一列的子查询
--单列只查询可以在任意一个地方使用 比如说 :
--select, from ,where ,order by....
--要求按照员工 department_name 进行排序
select
-- 查询工资比某个员工高的其他员工信息
--查询员工中工资大于本部门平均工资的员工的first_name,salary,department_id
select first_name,salary,department_id from employee outer
where salary >(
select avg(salary)
from employee where department_id = outer.department_id
);
--单列子查询( 相关子查询 )
-- 按照一行接着一行的顺序执行,主查询的每一行都会执行一次子查询 .
-- with 子句 :
--使用该子句可以避免在select语句中重复书写相同的语句块
--with 子句将该子句中的语句块一次执行并存储到用户表空间
--使用with子句可以提高查询效率
-- 索引 , 缓存 , with 子句 ( 本质上就是缓存 )
--查询公司中比Smith高的员工的信息
select * from employee where salary>(select salary from
employee where first_name='smith')
with smith_sal as(
select salary from
employee where first_name='smith'
);
select * from employee where salary>(select salary from smith_sal);
--当题目很庞大的时候,可以使用with语句拆分成很多模块
--查询公司中各部门的总工资大于公司中各部门平均总工资的部门的信息.
with dept_sumsal as(
select department_name, sum(salary) sun_sal01 from employee e, departments d where
d.department_id = e.department_id group by department_name
) ;
--
depart_avgsal as(
select sum(sun_sal01)/count(*) avg_sum_sal02 from dept_sumsal)
select * from depart_avgsal where sun_sal01>
(select avg_sum_sal02 from depart_avgsal)
-- 视图
-- 视图是从表中抽离出的逻辑相关的数据集合
-- view
--本章学习目标
-- 描述视图
-- 创建和修改视图的定义 , 删除视图
-- 从视图中查询数据
-- 通过视图插入,修改和删除数据
--视图是一张虚表
--视图建立在已有表的基础上,视图赖与建立的这些表称为基表
--向视图提供数据内容的语句为 select 语句 ,可以将视图理解为存储起来的 select 语句
--视图向用于提供基表数据的另一种表现形式 .
--视图的作用
-- 控制数据访问
-- 简化查询
--如何创建一个视图
create view emp_view03
as
select employee_id id,first_name name,department_id dp
from employee e,depatment d
where e.department_id = d.department;
--修改视图
--使用 create or replace view
--创建或替换
create or replace view emp_view03
as
select employee_id id,department_id dp
from employee e,depatment d
where e.department_id = d.department
with read only;
--屏蔽 DML 操作
--可以使用 with read only 选择屏蔽对视图的DML操作
--任何 DML 操作都会返回一个 oracle server 错误
--简单视图和复杂视图
-- 特性 简单视图 复杂视图
-- 表的数量 一个 多个
-- 函数 没有 有
-- 分组 没有 有
-- DML操作 可以 有时可以
create or replace view emp_view04
as
select department_name, avg(salary) avg_sal
from employee e ,departments d where
e.department_id = d.department
group by department_name;
视图中使用DML中的规定
.可以使用简单视图中执行DML操作
.当视图定义中包含以下元素之一不能使用delete:
-组函数
-group by 子句
-distinct 关键字
-rownum 伪列
在复杂视图中不能使用DML 操作
--原因 : 对于虚表的列的修改无法对应实际列的修改 ( 不绝对 ) 例如 avg(salary)
--对于简单的多表连接视图 ,可以使用增删查 ,但是不会影响基表 ,无法进行修改 ,会报异常 .
-- 删除视图
drop view emp_view01 ;
--练习 :
--1.查询员工表中salary前10 的员工信息
select * from (select * from employee order by salary desc) where rownum<=10
--说明 : rownum " 伪列" 数据本身并没有这样的列 ,是oracle数据库为每个数据表加上的列
--可表示行号,默认情况下,rownum 按主索引来排序,诺没有主索引则自然排序
--对于 rownum 只能使用<或者<=
--用 =,>,>= 都不能返回任何数据
--2.查询员工表salary10-20 的员工信息
select * from
(select rownum rn,temp.* from
(select * from employee e order by salary desc) temp where rownum<=20 )
where rn>10 and rn<20;
--测试
--1.使用表 employee创建视图 ,其中包括姓名,员工号,部门
create view emp_views
as
select first_name,employee_id,department_id from employee;
--2. 显示视图的结构
--3. 查询视图中全部内容
select * from emp_views1;
--4. 将视图中的数据限定在部门号 10 范围内
create view emp_views1
as
select * from (select * from employee order by salary desc) where rownum<=10
--5.将视图编程只读视图
create or replace view emp_views1
as
select * from (select * from employee order by salary desc) where rownum<=10
with read only
游标的使用
定义:在pl/sql程序中,对于处理多行记录的事务经常使用游标来实现
举例:打印出部门号为10号的所有员工的工资.
概念:为了处理sql语句,oracle必须分配一片叫做上下文(context area )的区域来处理
所必须的信息,其中包括要处理的行和数组,一个指向语句被分析以后的
表示形式的指针以及查询活动集合
游标:是一个指向上下文的句柄或指针.
显示游标
1.定义游标
2.打开游标
3.提取游标数据
4.关闭游标
-- 举例 :打印出部门号为10 号的所有员工的工资 .
游标的属性:
%found:布尔类型,当最近一次读记录时成功返回值为true
%notfound:布尔类型,与%found相反
%isopen: 布尔类型,当游标以打开时返回true
%rowcount :数字类型,返回以从游标读取的记录数.
游标的for循环
pl/sql语言提供了游标的for循环语句,自动执行游标的open,
fetch,close语句和循环语句的功能
-- set serveroutput on; 在命令窗口中使用
declare
--声明一个变量用来接收游标所有的数据
--v_emp_record emp_record ---变量名+类型
type emp_record is record(
v_sal employee.salary%type,
v_name employee.first_name%type
);
--定义游标
cursor emp_sal_cursor is select salary,first_name from employee where department_id=1016;
begin
for c in emp_sal_cursor loop
dbms_output.put_line('salary:'||c.salary||'first_name:'||c.first_name);
end loop;
end;
/*--打开游标
open emp_sal_cursor;
--提取游标
fetch emp_sal_cursor into v_emp_record;
while emp_sal_cursor%found loop
--打印出工资信息
dbms_output.put_line('salary:'||v_emp_record.v_sal||'first_name:'||v_emp_record.v_name);
fetch emp_sal_cursor into v_emp_record;
end loop;
--关闭游标
close emp_sal_cursor;
end;*/
练习:
利用游标,调整公司中员工的工资
工资范围 调整基础
0-5000 5%
5000-10000 4%
10000-15000 3%
15000- 2%
declare
--定义游标
cursor emp_sal_cursor is select first_name,salary from employee;
v_temp number(4,2);
v_emp_name employee.first_name%type;
v_emp_salary employee.salary%type;
begin
--打开游标
open emp_sal_cursor;
--提取游标数据
fetch emp_sal_cursor into v_emp_name,v_emp_salary;
--写业务逻辑
while emp_sal_cursor%found loop
if v_emp_salary<5000 then v_temp:=0.05;
elsif v_emp_salary<10000 then v_temp:=0.04;
elsif v_emp_salary<15000 then v_temp:=0.03;
else v_temp:=0.02;
end if;
dbms_output.put_line(v_emp_name||','||v_emp_salary);
update employee set salary = salary*(1+v_temp)
where first_name =v_emp_name;
dbms_output.put_line(v_emp_name||','||v_emp_salary);
fetch emp_sal_cursor into v_emp_name,v_emp_salary;
end loop;
close emp_sal_cursor;
end;
declare
--定义游标
cursor emp_sal_cursor is select first_name,salary from employee;
v_temp number(4,2);
v_emp_name employee.first_name%type;
v_emp_sal employee.salary%type;
begin
for c in emp_sal_cursor loop
if c.salary<5000 then v_temp:=0.05;
elsif c.salary<10000 then v_temp:=0.04;
elsif c.salary<15000 then v_temp:=0.03;
else v_temp:=0.02;
end if;
dbms_output.put_line(c.first_name||','||c.salary);
update employee
set salary=salary*(1+v_temp)
where first_name=c.first_name;
end loop;
end;
小结: 游标主要用于处理返回的多行记录(类似于java中的迭代器)
游标主要是配合存储函数一起使用,原因是游标可以将获取的数据保存
在指定的变量中,以供其他函数调用 .
--dbms_output_line 将必要的信息输出 ,以便对 " 存储函数 " 进行调试 ,
--只有将serveroutput 余量设为on 后,信息才能显示在屏幕上.
--作业 :
--1. 使用 for 循环改写上一题
--2 . 使用 sql 语句中 decode 函数改写上一题
Select first_name , decode (e.salary,1366.90,e.salary*(1.005))
salary from employee e;
1.PL/SQL函数
2.什么是记录类型
select * from employee;
-- 存储函数和存储过程
oracle提供了可以把ps/sql程序存储在数据库中,并可以在任何地方来运行它,
这样就叫做存储过程或函数.
.过程和函数的唯一区别是函数总向调用者返回数据,而过程则不返回数据.
-- 函数的 helloWorld : 返回一个 "helloWorld" 字符串
create or replace function hello_world
return varchar2
is
begin
return 'helloworld';
end;
--调用存储函数
begin
dbms_output.put_line(hello_world);
end;
set serveroutput on;
--写一个存储函数 , 返回当前时间
create or replace function get_sysdate
retrun date
is
--可以声明变量进行数据接收
v_date date;
begin
date:=sysdate;
retrun date;
end;
-- 定义函数,读取给定部门的工资总和 ,要求:部门号定义为参数 ,工资
--总额定义为返回值
--使用 cursor 游标
create or replace function get_sal(depton_id number)
return number
is
v_sumsal number(10,2):=0;
--使用游标 ( 返回的值有多条 )
cursor salary_cursor is select salary from employee where department_id=depton_id;
begin
--开始书写逻辑
for c in salary_cursor loop
v_sumsal:=v_sumsal+c.salary;
end loop;
return v_sumsal;
end;
select *from employee;
-- 触发器
触发器是许多关系型数据库系统提供的一项技术,在oracle系统里,触发器类似于过程和函数,
都有声明执行和异常处理过程的pl/spl块
触发器在数据库以独立的对象存储,他与存储过程不同,
存储过程通过其他程序来启动运行,而触发器有一个事件来启动运行
,即触发器是当某个事件发生时,自动地隐式运行
oracle事件:对数据库的的表进行增删改查等操作.
--触发器的组成
.触发事件:即在任何情况下触发Trigger
.触发时间:即在触发时间发生前厚实之后触发
.触发器本身:即触发器本身的目的和意图
.触发频率:说明触发器内定义的动作被执行次数
--编写一个触发器 ,在向employee 表中插入记录时,打印 'helloworld '
create or replace trigger emp_trigger
after
insert on employee for each row
begin
dbms_output.put_line('helloworld');
end;
select * from employee ;