--等值连接
--查询员工信息: 员工号 姓名 月薪 部门名称
select p.deptno,p.ename,p.sal ,t.dname from emp p,dept t where p.deptno=t.deptno;
--不等值连接
--查询员工信息: 员工号 姓名 月薪 工资级别
select e.deptno,e.ename,e.sal,s.grade from emp e,salgrade s where e.sal between s.losal and s.hisal;
--外连接
--按部门统计员工人数: 部门号 部门名称 人数
select d.deptno,d.dname,count(d.deptno) from emp e,dept d where e.deptno=d.deptno group by d.deptno,d.dname;
---希望: 在最后的结果中,包含某些不成立的记录
---外连接:
---左外连接: 当where e.deptno=d.deptno不成立的时候,等号左边所代表的表 任然被包含
----写法: where e.deptno=d.deptno(+)
select d.deptno,d.dname,count(e.deptno) from emp e,dept d where e.deptno=d.deptno(+) group by d.deptno,d.dname;
---右外连接: 当where e.deptno=d.deptno不成立的时候,等号右边所代表的表 任然被包含
---写法:where e.deptno(+)=d.deptno
select d.deptno,d.dname,count(e.deptno) from emp e,dept d where e.deptno(+)=d.deptno group by d.deptno,d.dname;
--自连接
---查询员工信息:***的老板是***
--自连接:通过表的别名,将同一张表视为多张表
select e.ename||‘的老板是‘||p.ename from emp e,emp p where e.mgr=p.empno;
--层次查询
select level,empno,ename,sal,mgr from emp connect by prior empno=mgr start with mgr is null order by 1;
--查询工资比SCOTT高的员工信息
select e.* from emp e where e.sal > (select sal from emp p where p.ename=‘SCOTT‘);
注意的问题
--- 1. 括号
--- 2. 合理的书写风格
--- 3. 可以主查询的where select from having后面放置子查询
--- 4. 不可以在主查询的group by后面放置子查询
--- 5. 强调from后面的子查询
--- 6. 主查询和子查询可以不是同一张表,只要子查询返回的结果 主查询可以使用即可
--- 7. 一般不在子查询使用order by,但在Top-N分析问题中 必须使用order by
--- 8. 一般先执行子查询,再执行主查询;但相关子查询除外
--- 9. 单行子查询只能使用单行操作符 多行子查询只能使用多行操作符
--- 10. 子查询中null
-- 3. 可以主查询的where select from having后面放置子查询
select e.ename,e.deptno,(select job from emp where empno=7839) from emp e ;
--5. 强调from后面的子查询
--查询员工的姓名和薪水
select e.ename,e.sal from emp e;
select f.* from (select e.ename,e.sal ,e.sal*12 from emp e) f;
--6. 主查询和子查询可以不是同一张表,只要子查询返回的结果 主查询可以使用即可
--查询部门名称为SALES的员工信息
select e.* from emp e where e.deptno =(select deptno from dept where dname=‘SALES‘);
--优化5:理论上,尽量使用多表查询
--in 在集合中
--查询部门名称是SALES和ACCOUNTING的员工
select * from emp where deptno in (select deptno from dept where dname=‘SALES‘ or dname=‘ACCOUNTING‘);
select e.* from emp e,dept d where e.deptno=d.deptno and (d.dname=‘SALES‘ or d.dname=‘ACCOUNTING‘);
--any: 和集合中 任意一个值比较
--查询工资比30号部门任意一个员工高的员工信息
select e.* from emp e where e.sal> any (select sal from emp where deptno=30);
select e.* from emp e where e.sal> (select min(sal) from emp where deptno=30);
--all:和集合的所有值比较
--查询工资比30号部门所有员工高的员工信息
select e.* from emp e where e.sal> all (select sal from emp where deptno=30);
select e.* from emp e where e.sal> (select max(sal) from emp where deptno=30);
--多行子查询中null
--查询不是老板的员工信息
select e.* from emp e where e.empno in (select mgr from emp );
select e.* from emp e where e.empno not in (select mgr from emp where mgr is not null );
---查询部门号是10和20的员工信息
select * from emp e where e.deptno in (10,20);
select empno,ename,job,sal from emp where deptno=10
union
select empno,ename,job,sal from emp where deptno=20;
select deptno,job,sum(sal) from emp group by rollup(deptno,job);
select deptno,job,sum(sal) from emp group by deptno,job
union
select deptno,to_char(null),sum(sal) from emp group by deptno
union
select to_number(null),to_char(null),sum(sal) from emp ;
-----工资最高的前三名
select rownum, t.ename,t.sal
from
(select ename,sal,row_number() over (order by sal desc) rn from emp) t
where rn<=3;
select * from (select * from emp order by sal desc) where rownum<=3;
--第一题
select * from (
select rownum r,u.* from
(select ename,deptno,sal from emp order by sal desc) u
where rownum<=8) q where r>5
--第二题
select e.ename,e.sal,o.m from emp e,(select deptno, avg(sal) m from emp group by deptno) o where e.deptno=o.deptno and e.sal>o.m;
select e.ename,e.sal,(select avg(sal) m from emp where deptno=e.deptno) avga from emp e where e.sal>(select avg(sal) from emp where deptno=e.deptno);
--第三题
--组函数 行转列 wm_concat
select * from emp;
select deptno,wm_concat(ename) from emp group by deptno;
select count(*) ,sum(decode(to_char(hiredate,‘RR‘),‘80‘,1,0)) "1980",sum(decode(to_char(hiredate,‘RR‘),‘81‘,1,0)) "1981",sum(decode(to_char(hiredate,‘RR‘),‘82‘,1,0)) "1982",sum(decode(to_char(hiredate,‘RR‘),‘87‘,1,0)) "1987" from emp;
---管理员登录
sqlplus sys/你的密码 as sysdba (密码认证)
sqlplus / as sysdba (主机认证 优先)
---解锁
alter user scott account unlock;
---改密码
alter user scott identified by 新密码;
---SQL类型
---1. DML(Data Manipulation Lanuage 数据操作语言): select insert update delete
---2. DDL(Data Definition Language 数据定义语言): create/alter/drop/truncate table create/drop view/sequence/index/synonym
---3. DCL(Data Control Language 数据控制语言): commit rollback
--插入数据 insert
insert into emp (empno,ename,sal ,deptno) values(1001,‘Tom‘,6000,20);
--隐式/显式插入null
-----地址符 &
insert into emp (empno,ename,sal ,deptno) values(&empno,‘&ename‘,&sal,&deptno);
select empno,ename,deptno from &t;
rollback;
--批处理
create table emp10 as select * from emp where 1=2;
select * from emp10;
--一次性从emp中 将所有10号部门的员工插入到emp10
insert into emp10 select * from emp where deptno=10;
--更新数据
--删除数据
----delete 和truncate的区别
---1. delete逐条删除 truncate 先摧毁表 再重建
---2. **** delete 是DML(可以回滚),truncate是DDL(不可以回滚)
---3. delete不会释放空间 truncate会
---4. delete会产生碎片 truncate不会
---5. delete可以闪回,truncate不可以
create table testdelete(tid number ,tname varchar2(20));
CREATE SEQUENCE SI_EXTERNAL_SEQ --SI_EXTERNAL_SEQ要创建的sequence的名字
INCREMENT BY 1 -- 每次加几个
START WITH 1 -- 从1开始计数
NOMAXVALUE -- 不设置最大值
NOCYCLE -- 一直累加,不循环
CACHE 10;
insert into testdelete values(SI_EXTERNAL_SEQ.NEXTVAL,‘aaa‘);
commit;
select * from testdelete;
set timing on
create table testdelete2 as select * from testdelete;
------保存点
create table testsavepoint
(tid number,tname varchar2(20));
set feedback on
insert into testsavepoint values(1,‘Tom‘);
insert into testsavepoint values(2,‘Mary‘);
savepoint a;
insert into testsavepoint values(3,‘Moke‘);
select * from testsavepoint;
rollback to savepoint a;
commit;
---
create table test1(
tid number,
tname varchar2(20),
hirdate date default sysdate
)
insert into test1(tid,tname) values(1,‘tom‘);
select * from test1;
--行地址
select rowid,empno,ename,job from emp;
--保存20号部门的员工
create table emp20 as select * from emp where deptno=20;
select * from emp20;
--创建表: 员工号 姓名 月薪 年薪 部门名称
create table empinfo as select e.empno,e.ename,e.sal,e.sal*12 niansal ,d.dname from dept d,emp e where d.deptno=e.deptno;
select * from empinfo;
--修改表: 追加新列 修改列 删除列 重名列
select * from test1;
alter table test1 add age2 number;
alter table test1 modify age varchar2(40);
alter table test1 drop column age;
alter table test1 rename column tid to ttid;
select * from tab;
drop table test1;
--Oracle的回收站
select * from recyclebin;
---清空回收站
purge recyclebin;
--drop table test1 purge; --> 不经过回收站直接删除
--注意: 管理员没有回收站
--检查性约束
create table student(
sid number primary key,
sname varchar2(40) not null,
age number check (age>0),
gender varchar2(4) check(gender in (‘男‘,‘女‘))
)
select * from student;
insert into student(sid,sname,age,gender) values(2,‘aaa‘,25,‘a‘);
commit;
create table teacher(
sid number constraint t_pk primary key,
sname varchar2(40) constraint t_name not null,
age number constraint t_age check (age>0),
gender varchar2(4) constraint t_gender check(gender in (‘男‘,‘女‘))
)
insert into teacher(sid,sname,age,gender) values(2,‘aaa‘,25,‘a‘);
----Hello World
set serveroutput on
declare
begin
dbms_output.put_line(‘Hello World‘);
end;
/
-----if语句
set serveroutput on
accept num prompt ‘请输入一个数字‘;
declare
pnum number :=#
begin
if pnum=1 then dbms_output.put_line(‘输入的值为1‘);
elsif pnum=2 then dbms_output.put_line(‘输入的值为2‘);
elsif pnum=3 then dbms_output.put_line(‘输入的值为3‘);
else dbms_output.put_line(‘输入的值为其它‘);
end if;
end;
/
--带参数的光标
--查询某个部门中员工的姓名
set serveroutput on
accept num prompt ‘请输入一个数字‘;
declare
cursor cemp(dmo number) is select ename from emp where deptno=dmo;
pname emp.ename%type;
pnum number :=#
begin
open cemp(pnum);
loop
fetch cemp into pname;
exit when cemp%notfound;
dbms_output.put_line(pname);
end loop;
close cemp;
end;
/
-----涨工资 总裁1000 经理800 其他400
set serveroutput on
declare
cursor cemp is select empno,empjob from emp;
pempno emp.empno%type;
pjob emp.empjob%type;
begin
open cemp;
loop
fetch cemp into pempno,pjob;
exit when cemp%notfound;
if pjob=‘PRESIDENT‘ then update emp set sal=sal+1000 where empno=pempno;
elsif pjob=‘MANAGER‘ then update emp set sal=sal+800 where empno=pempno;
else update emp set sal=sal+400 where empno=pempno;
end if;
end loop;
close cemp;
commit;
dbms_output.put_line(‘完成!‘);
end;
/
select * from emp;
-----使用游标查询员工姓名和工资,并打印
/*
1. 光标的属性
%isopen: 是否打开
%rowcount: 行数
%notfound: 没有记录
2. 默认允许一次打开300个光标(修改光标: 第四天 管理方案)
SQL> show parameters cursor
NAME TYPE VALUE
------------------------------------ ----------- -------
cursor_sharing string EXACT
cursor_space_for_time boolean FALSE
open_cursors integer 300
session_cached_cursors integer 20
*/
show parameters cursor;
set serveroutput on
declare
cursor cemp is select ename,sal from emp;
pename emp.ename%type;
psal emp.sal%type;
begin
open cemp;
loop
fetch cemp into pename,psal;
exit when cemp%notfound;
dbms_output.put_line(pename||‘的薪水为‘||psal);
end loop;
close cemp;
end;
/
--------查询并打印7839的姓名和薪水
--记录型变量 代表一行
set serveroutput on
declare
rec emp%rowtype;
begin
select * into rec from emp where empno=7839;
dbms_output.put_line(rec.empno||‘aaaa‘||rec.sal);
end;
/
实例1:统计每年入职的员工个数。
set serveroutput on
declare
cursor cemp is select to_char(hiredate,‘RR‘) from emp;
phiredate varchar2(4);
count80 number :=0;
count81 number :=0;
count82 number :=0;
count87 number :=0;
begin
open cemp;
loop
fetch cemp into phiredate;
exit when cemp%notfound;
if phiredate=‘80‘ then count80:=count80+1;
elsif phiredate=‘81‘ then count81:=count81+1;
elsif phiredate=‘82‘ then count82:=count82+1;
else count87:=count87+1;
end if;
end loop;
close cemp;
dbms_output.put_line(‘total‘||(count80+count81+count82+count87));
dbms_output.put_line(count80);
dbms_output.put_line(count81);
dbms_output.put_line(count82);
dbms_output.put_line(count87);
end;
/
---为员工长工资。从最低工资调起每人长10%,但工资总额不能超过5万元,
----请计算长工资的人数和长工资后的工资总额,并输出输出长工资人数及工资总额。
set serveroutput on
declare
cursor cemp is select empno,sal from emp;
pempno emp.empno%type;
psal emp.sal%type;
countEmp number :=0;
salTotal number ;
begin
select sum(sal) into salTotal from emp;
open cemp;
loop
exit when salTotal>200000;
fetch cemp into pempno,psal;
exit when cemp%notfound;
update emp set sal=sal*1.1 where empno=pempno;
countEmp :=countEmp+1;
if salTotal+psal*0.1<200000 then salTotal :=salTotal+psal*0.1;
else exit;
end if;
end loop;
close cemp;
commit;
dbms_output.put_line(‘人数:‘||countEmp||‘ 工资总额:‘||salTotal);
end;
/
-----用PL/SQL语言编写一程序,实现按部门分段(6000以上、(6000,3000)、3000元以下)
----统计各工资段的职工人数、以及各部门的工资总额(工资总额中不包括奖金)
set serveroutput on
declare
cursor cdept is select deptno from dept;
pdeptno dept.deptno%type;
cursor cemp(dno number) is select sal from emp where deptno=dno;
psal emp.sal%type;
count1 number;count2 number;count3 number;
salTotal number;
begin
open cdept;
loop
fetch cdept into pdeptno;
exit when cdept%notfound;
count1 :=0;count2 :=0;count3 :=0;
select sum(sal) into salTotal from emp where deptno=pdeptno;
open cemp(pdeptno);
loop
fetch cemp into psal;
exit when cemp%notfound;
if psal<3000 then count1 :=count1+1;
elsif psal>3000 and psal<6000 then count2 :=count2+1;
else count3 :=count3+1;
end if;
end loop;
close cemp;
insert into msg1 values(pdeptno,count1,count2,count3,nvl(salTotal,0));
end loop;
close cdept;
commit;
dbms_output.put_line(‘完成‘);
end;
/
create table msg1(
n1 number,
n2 number,
n3 number,
n4 number,
n5 number
)
select * from msg1;
-----被0除
set serveroutput on
declare
pnum number;
begin
pnum :=1/0;
exception
when Zero_Divide then dbms_output.put_line(‘1:0不能做被除数‘);
dbms_output.put_line(‘2:0不能做被除数‘);
when Value_error then dbms_output.put_line(‘算术或转换错误‘);
when others then dbms_output.put_line(‘其他例外‘);
end;
/
----循环
set serveroutput on
declare
pnum number;
begin
pnum :=0;
loop
exit when pnum>10;
dbms_output.put_line(pnum);
pnum :=pnum+1;
end loop;
end;
/
-----查询并打印7839的姓名和薪水
set serveroutput on
declare
pename emp.ename%type;
psal emp.sal%type;
begin
select ename,sal into pename,psal from emp where empno=7839;
dbms_output.put_line(pename||‘的薪水是‘||psal);
end;
/
------查询50号部门的员工
set serveroutput on
declare
cursor cemp is select ename from emp where deptno=30;
pename emp.ename%type;
no_emp_found exception;
begin
open cemp;
fetch cemp into pename;
if cemp%notfound then
raise no_emp_found;
end if;
close cemp;
exception
when no_emp_found then dbms_output.put_line(‘没有找到员工‘);
when others then dbms_output.put_line(‘其他例外‘);
end;
/
select * from emp;
/*
create [or replace] PROCEDURE 过程名(参数列表)
AS
PLSQL子程序体;
查询并返回某个员工的姓名 月薪和职位
思考: out参数太多???
*/
create or replace procedure queryEmpInfo(
eno in number,
pename out varchar2,
psal out number,
pjob out varchar2
)
as
begin
select ename,sal,empjob into pename,psal,pjob from emp where empno=eno;
end;
/
/*
实施复杂的安全性检查
禁止在非工作时间 往emp表中插入数据
CREATE [or REPLACE] TRIGGER 触发器名
{BEFORE | AFTER}
{DELETE | INSERT | UPDATE [OF 列名]}
ON 表名
PLSQL 块
周末:to_char(sysdate,‘day‘) in (‘星期六‘,‘星期日‘)
上班前 下班后: to_number(to_char(sysdate,‘hh24‘)) not between 9 and 18
*/
create or replace trigger securityEmp
before insert
on emp
begin
if to_char(sysdate,‘day‘) in (‘星期三‘,‘星期六‘) or
to_number(to_char(sysdate,‘hh24‘)) not between 9 and 18 then
raise_application_error(-20001,‘不能在非工作时间插入数据‘);
end if;
end;
/
select * from emp;
insert into emp(empno,ename,empjob,sal) values(100,‘hhh‘,‘manager‘,8000);
select * from user_source where name like ‘%SECURITYEMP%‘;
drop trigger checksal;
/*
数据确认
涨后的薪水不能少于涨前的薪水
CREATE [or REPLACE] TRIGGER 触发器名
{BEFORE | AFTER}
{DELETE | INSERT | UPDATE [OF 列名]}
ON 表名
[FOR EACH ROW [WHEN(条件) ] ]
PLSQL 块
*/
create or replace trigger checksal
before update
on emp
for each row
begin
if :new.sal<:old.sal then
raise_application_error(-20002,‘涨后的薪水不能少于涨前的薪水.涨前:‘||:old.sal||‘ 涨后:‘||:new.sal);
end if;
end;
/
update emp set sal=sal-100 where empno=7839;
/*
CREATE [OR REPLACE] FUNCTION 函数名(参数列表)
RETURN 函数值类型
AS
PLSQL子程序体;
查询某个员工的年收入
*/
create or replace function queryEmpIncome(eno in number)
return number
as
psal emp.sal%type;
pcomm emp.comm%type;
begin
select sal,comm into psal,pcomm from emp where empno=eno;
return psal*12+nvl(pcomm,0);
end;
/
/*
create [or replace] PROCEDURE 过程名(参数列表)
AS
PLSQL子程序体;
为指定的员工涨100块钱 并打印涨前和涨后的薪水
*/
create or replace procedure raiseSalary(
eno in number
)
as
psal emp.sal%type;
begin
select sal into psal from emp where empno=eno;
update emp set sal=sal+100 where empno=eno;
dbms_output.put_line(‘涨前:‘||psal||‘ 涨后:‘||(psal+100));
end;
/
create or replace trigger sayNewEmp
after insert on emp
declare
begin
dbms_output.put_line(‘插入数据!‘);
end;
/
delete from emp where empno=1000;
select * from emp;
select * from user_source where type=‘CURSOR‘;
/*
1.错误的删除了数据,并且已经提交
2.错误的删除了表drop table
3.如何获取表上的历史记录
4.如何撤销已经提交的事务
闪回的类型
1.闪回表:将表返回到过去的一个时间上
2.闪回删除:操作oracle的回收站
3.闪回版本查询:表上的历史记录
4.闪回事务查询:获取表上的一个UNDO_SQL
5.闪回数据库:将数据库返回到过去的一个时间上
6.闪回归档日志
*/
---查询没有提交的数据
show parameter undo;
----设置闪回时间 scope的取值:memoery(本次回话) spfile(重启后生效) both()
alter system set undo_retention=1200 scope=both;
---系统改变号SCN----6952590965600 6952590966674
select to_char(sysdate,‘yyyy-mm-dd hh24:mi:ss:mm‘) 时间,
timestamp_to_scn(sysdate) SCN
from dual;
---闪回表
create table flashback_table (fid number,fname varchar2(40));
insert into flashback_table values(1,‘tom‘);
insert into flashback_table values(2,‘marry‘);
insert into flashback_table values(3,‘mike‘);
delete from flashback_table where fid=2;
select * from flashback_table;
---启动行移动ALTER TABLE table_name ENABLE ROW MOVEMENT
alter table flashback_table enable row movement;
flashback table flashback_table to SCN 6952590966674;
---如何获取离操作最近的一个时间或者SCN?
select * from tab;
drop table EMP20 purge;
----闪回删除的表
flashback table MSG1 to before drop rename to msg5 ;
create table MSG1(mid number,mname varchar2(30));
select * from msg4;
show recyclebin;
purge recyclebin;
-------管理员没有回收站
create table ggg(mid number,mname varchar2(30));
insert into ggg values(1,‘ssss‘);
drop table ggg;
select * from ggg;
flashback table ggg to before drop ;
flashback table ggg to before drop rename to msg5 ;
select * from msg5;
-----返回版本
create table version_table(tid number,tname varchar2(30));
insert into version_table values(1,‘tom‘);
insert into version_table values(2,‘mary‘);
insert into version_table values(3,‘mike‘);
update version_table set tname=‘mary123‘ where tid=2;
select * from version_table;
-----查询返回版本的语法
select tid,tname,versions_operation,versions_starttime,versions_endtime,versions_xid from version_table versions between timestamp minvalue and maxvalue;
----闪回事务查询
create table tracation_table(tid number,tname varchar2(30));
insert into tracation_table values(1,‘tom‘);
insert into tracation_table values(2,‘mary‘);
insert into tracation_table values(3,‘mike‘);
update tracation_table set tname=‘dfdfd‘ where tid=2;
select tid,tname,versions_operation,versions_starttime,versions_endtime,versions_xid from tracation_table versions between timestamp minvalue and maxvalue;
select operation,undo_sql from flashback_transaction_query where xid=‘0B00080016DF0000‘;
exp scott/tiger @10.4.237.4:1521:orcl file=f:/a.dmp log=f:/log.log tables=dept,emp
--等值连接
--查询员工信息: 员工号 姓名 月薪 部门名称
select p.deptno,p.ename,p.sal ,t.dname from emp p,dept t where p.deptno=t.deptno;
--不等值连接
--查询员工信息: 员工号 姓名 月薪 工资级别
select e.deptno,e.ename,e.sal,s.grade from emp e,salgrade s where e.sal between s.losal and s.hisal;
--外连接
--按部门统计员工人数: 部门号 部门名称 人数
select d.deptno,d.dname,count(d.deptno) from emp e,dept d where e.deptno=d.deptno group by d.deptno,d.dname;
---希望: 在最后的结果中,包含某些不成立的记录
---外连接:
---左外连接: 当where e.deptno=d.deptno不成立的时候,等号左边所代表的表 任然被包含
----写法: where e.deptno=d.deptno(+)
select d.deptno,d.dname,count(e.deptno) from emp e,dept d where e.deptno=d.deptno(+) group by d.deptno,d.dname;
---右外连接: 当where e.deptno=d.deptno不成立的时候,等号右边所代表的表 任然被包含
---写法:where e.deptno(+)=d.deptno
select d.deptno,d.dname,count(e.deptno) from emp e,dept d where e.deptno(+)=d.deptno group by d.deptno,d.dname;
--自连接
---查询员工信息:***的老板是***
--自连接:通过表的别名,将同一张表视为多张表
select e.ename||‘的老板是‘||p.ename from emp e,emp p where e.mgr=p.empno;
--层次查询
select level,empno,ename,sal,mgr from emp connect by prior empno=mgr start with mgr is null order by 1;
--查询工资比SCOTT高的员工信息
select e.* from emp e where e.sal > (select sal from emp p where p.ename=‘SCOTT‘);
注意的问题
--- 1. 括号
--- 2. 合理的书写风格
--- 3. 可以主查询的where select from having后面放置子查询
--- 4. 不可以在主查询的group by后面放置子查询
--- 5. 强调from后面的子查询
--- 6. 主查询和子查询可以不是同一张表,只要子查询返回的结果 主查询可以使用即可
--- 7. 一般不在子查询使用order by,但在Top-N分析问题中 必须使用order by
--- 8. 一般先执行子查询,再执行主查询;但相关子查询除外
--- 9. 单行子查询只能使用单行操作符 多行子查询只能使用多行操作符
--- 10. 子查询中null
-- 3. 可以主查询的where select from having后面放置子查询
select e.ename,e.deptno,(select job from emp where empno=7839) from emp e ;
--5. 强调from后面的子查询
--查询员工的姓名和薪水
select e.ename,e.sal from emp e;
select f.* from (select e.ename,e.sal ,e.sal*12 from emp e) f;
--6. 主查询和子查询可以不是同一张表,只要子查询返回的结果 主查询可以使用即可
--查询部门名称为SALES的员工信息
select e.* from emp e where e.deptno =(select deptno from dept where dname=‘SALES‘);
--优化5:理论上,尽量使用多表查询
--in 在集合中
--查询部门名称是SALES和ACCOUNTING的员工
select * from emp where deptno in (select deptno from dept where dname=‘SALES‘ or dname=‘ACCOUNTING‘);
select e.* from emp e,dept d where e.deptno=d.deptno and (d.dname=‘SALES‘ or d.dname=‘ACCOUNTING‘);
--any: 和集合中 任意一个值比较
--查询工资比30号部门任意一个员工高的员工信息
select e.* from emp e where e.sal> any (select sal from emp where deptno=30);
select e.* from emp e where e.sal> (select min(sal) from emp where deptno=30);
--all:和集合的所有值比较
--查询工资比30号部门所有员工高的员工信息
select e.* from emp e where e.sal> all (select sal from emp where deptno=30);
select e.* from emp e where e.sal> (select max(sal) from emp where deptno=30);
--多行子查询中null
--查询不是老板的员工信息
select e.* from emp e where e.empno in (select mgr from emp );
select e.* from emp e where e.empno not in (select mgr from emp where mgr is not null );
---查询部门号是10和20的员工信息
select * from emp e where e.deptno in (10,20);
select empno,ename,job,sal from emp where deptno=10
union
select empno,ename,job,sal from emp where deptno=20;
select deptno,job,sum(sal) from emp group by rollup(deptno,job);
select deptno,job,sum(sal) from emp group by deptno,job
union
select deptno,to_char(null),sum(sal) from emp group by deptno
union
select to_number(null),to_char(null),sum(sal) from emp ;
-----工资最高的前三名
select rownum, t.ename,t.sal
from
(select ename,sal,row_number() over (order by sal desc) rn from emp) t
where rn<=3;
select * from (select * from emp order by sal desc) where rownum<=3;
--第一题
select * from (
select rownum r,u.* from
(select ename,deptno,sal from emp order by sal desc) u
where rownum<=8) q where r>5
--第二题
select e.ename,e.sal,o.m from emp e,(select deptno, avg(sal) m from emp group by deptno) o where e.deptno=o.deptno and e.sal>o.m;
select e.ename,e.sal,(select avg(sal) m from emp where deptno=e.deptno) avga from emp e where e.sal>(select avg(sal) from emp where deptno=e.deptno);
--第三题
--组函数 行转列 wm_concat
select * from emp;
select deptno,wm_concat(ename) from emp group by deptno;
select count(*) ,sum(decode(to_char(hiredate,‘RR‘),‘80‘,1,0)) "1980",sum(decode(to_char(hiredate,‘RR‘),‘81‘,1,0)) "1981",sum(decode(to_char(hiredate,‘RR‘),‘82‘,1,0)) "1982",sum(decode(to_char(hiredate,‘RR‘),‘87‘,1,0)) "1987" from emp;
---管理员登录
sqlplus sys/你的密码 as sysdba (密码认证)
sqlplus / as sysdba (主机认证 优先)
---解锁
alter user scott account unlock;
---改密码
alter user scott identified by 新密码;
---SQL类型
---1. DML(Data Manipulation Lanuage 数据操作语言): select insert update delete
---2. DDL(Data Definition Language 数据定义语言): create/alter/drop/truncate table create/drop view/sequence/index/synonym
---3. DCL(Data Control Language 数据控制语言): commit rollback
--插入数据 insert
insert into emp (empno,ename,sal ,deptno) values(1001,‘Tom‘,6000,20);
--隐式/显式插入null
-----地址符 &
insert into emp (empno,ename,sal ,deptno) values(&empno,‘&ename‘,&sal,&deptno);
select empno,ename,deptno from &t;
rollback;
--批处理
create table emp10 as select * from emp where 1=2;
select * from emp10;
--一次性从emp中 将所有10号部门的员工插入到emp10
insert into emp10 select * from emp where deptno=10;
--更新数据
--删除数据
----delete 和truncate的区别
---1. delete逐条删除 truncate 先摧毁表 再重建
---2. **** delete 是DML(可以回滚),truncate是DDL(不可以回滚)
---3. delete不会释放空间 truncate会
---4. delete会产生碎片 truncate不会
---5. delete可以闪回,truncate不可以
create table testdelete(tid number ,tname varchar2(20));
CREATE SEQUENCE SI_EXTERNAL_SEQ --SI_EXTERNAL_SEQ要创建的sequence的名字
INCREMENT BY 1 -- 每次加几个
START WITH 1 -- 从1开始计数
NOMAXVALUE -- 不设置最大值
NOCYCLE -- 一直累加,不循环
CACHE 10;
insert into testdelete values(SI_EXTERNAL_SEQ.NEXTVAL,‘aaa‘);
commit;
select * from testdelete;
set timing on
create table testdelete2 as select * from testdelete;
------保存点
create table testsavepoint
(tid number,tname varchar2(20));
set feedback on
insert into testsavepoint values(1,‘Tom‘);
insert into testsavepoint values(2,‘Mary‘);
savepoint a;
insert into testsavepoint values(3,‘Moke‘);
select * from testsavepoint;
rollback to savepoint a;
commit;
---
create table test1(
tid number,
tname varchar2(20),
hirdate date default sysdate
)
insert into test1(tid,tname) values(1,‘tom‘);
select * from test1;
--行地址
select rowid,empno,ename,job from emp;
--保存20号部门的员工
create table emp20 as select * from emp where deptno=20;
select * from emp20;
--创建表: 员工号 姓名 月薪 年薪 部门名称
create table empinfo as select e.empno,e.ename,e.sal,e.sal*12 niansal ,d.dname from dept d,emp e where d.deptno=e.deptno;
select * from empinfo;
--修改表: 追加新列 修改列 删除列 重名列
select * from test1;
alter table test1 add age2 number;
alter table test1 modify age varchar2(40);
alter table test1 drop column age;
alter table test1 rename column tid to ttid;
select * from tab;
drop table test1;
--Oracle的回收站
select * from recyclebin;
---清空回收站
purge recyclebin;
--drop table test1 purge; --> 不经过回收站直接删除
--注意: 管理员没有回收站
--检查性约束
create table student(
sid number primary key,
sname varchar2(40) not null,
age number check (age>0),
gender varchar2(4) check(gender in (‘男‘,‘女‘))
)
select * from student;
insert into student(sid,sname,age,gender) values(2,‘aaa‘,25,‘a‘);
commit;
create table teacher(
sid number constraint t_pk primary key,
sname varchar2(40) constraint t_name not null,
age number constraint t_age check (age>0),
gender varchar2(4) constraint t_gender check(gender in (‘男‘,‘女‘))
)
insert into teacher(sid,sname,age,gender) values(2,‘aaa‘,25,‘a‘);
----Hello World
set serveroutput on
declare
begin
dbms_output.put_line(‘Hello World‘);
end;
/
-----if语句
set serveroutput on
accept num prompt ‘请输入一个数字‘;
declare
pnum number :=#
begin
if pnum=1 then dbms_output.put_line(‘输入的值为1‘);
elsif pnum=2 then dbms_output.put_line(‘输入的值为2‘);
elsif pnum=3 then dbms_output.put_line(‘输入的值为3‘);
else dbms_output.put_line(‘输入的值为其它‘);
end if;
end;
/
--带参数的光标
--查询某个部门中员工的姓名
set serveroutput on
accept num prompt ‘请输入一个数字‘;
declare
cursor cemp(dmo number) is select ename from emp where deptno=dmo;
pname emp.ename%type;
pnum number :=#
begin
open cemp(pnum);
loop
fetch cemp into pname;
exit when cemp%notfound;
dbms_output.put_line(pname);
end loop;
close cemp;
end;
/
-----涨工资 总裁1000 经理800 其他400
set serveroutput on
declare
cursor cemp is select empno,empjob from emp;
pempno emp.empno%type;
pjob emp.empjob%type;
begin
open cemp;
loop
fetch cemp into pempno,pjob;
exit when cemp%notfound;
if pjob=‘PRESIDENT‘ then update emp set sal=sal+1000 where empno=pempno;
elsif pjob=‘MANAGER‘ then update emp set sal=sal+800 where empno=pempno;
else update emp set sal=sal+400 where empno=pempno;
end if;
end loop;
close cemp;
commit;
dbms_output.put_line(‘完成!‘);
end;
/
select * from emp;
-----使用游标查询员工姓名和工资,并打印
/*
1. 光标的属性
%isopen: 是否打开
%rowcount: 行数
%notfound: 没有记录
2. 默认允许一次打开300个光标(修改光标: 第四天 管理方案)
SQL> show parameters cursor
NAME TYPE VALUE
------------------------------------ ----------- -------
cursor_sharing string EXACT
cursor_space_for_time boolean FALSE
open_cursors integer 300
session_cached_cursors integer 20
*/
show parameters cursor;
set serveroutput on
declare
cursor cemp is select ename,sal from emp;
pename emp.ename%type;
psal emp.sal%type;
begin
open cemp;
loop
fetch cemp into pename,psal;
exit when cemp%notfound;
dbms_output.put_line(pename||‘的薪水为‘||psal);
end loop;
close cemp;
end;
/
--------查询并打印7839的姓名和薪水
--记录型变量 代表一行
set serveroutput on
declare
rec emp%rowtype;
begin
select * into rec from emp where empno=7839;
dbms_output.put_line(rec.empno||‘aaaa‘||rec.sal);
end;
/
实例1:统计每年入职的员工个数。
set serveroutput on
declare
cursor cemp is select to_char(hiredate,‘RR‘) from emp;
phiredate varchar2(4);
count80 number :=0;
count81 number :=0;
count82 number :=0;
count87 number :=0;
begin
open cemp;
loop
fetch cemp into phiredate;
exit when cemp%notfound;
if phiredate=‘80‘ then count80:=count80+1;
elsif phiredate=‘81‘ then count81:=count81+1;
elsif phiredate=‘82‘ then count82:=count82+1;
else count87:=count87+1;
end if;
end loop;
close cemp;
dbms_output.put_line(‘total‘||(count80+count81+count82+count87));
dbms_output.put_line(count80);
dbms_output.put_line(count81);
dbms_output.put_line(count82);
dbms_output.put_line(count87);
end;
/
---为员工长工资。从最低工资调起每人长10%,但工资总额不能超过5万元,
----请计算长工资的人数和长工资后的工资总额,并输出输出长工资人数及工资总额。
set serveroutput on
declare
cursor cemp is select empno,sal from emp;
pempno emp.empno%type;
psal emp.sal%type;
countEmp number :=0;
salTotal number ;
begin
select sum(sal) into salTotal from emp;
open cemp;
loop
exit when salTotal>200000;
fetch cemp into pempno,psal;
exit when cemp%notfound;
update emp set sal=sal*1.1 where empno=pempno;
countEmp :=countEmp+1;
if salTotal+psal*0.1<200000 then salTotal :=salTotal+psal*0.1;
else exit;
end if;
end loop;
close cemp;
commit;
dbms_output.put_line(‘人数:‘||countEmp||‘ 工资总额:‘||salTotal);
end;
/
-----用PL/SQL语言编写一程序,实现按部门分段(6000以上、(6000,3000)、3000元以下)
----统计各工资段的职工人数、以及各部门的工资总额(工资总额中不包括奖金)
set serveroutput on
declare
cursor cdept is select deptno from dept;
pdeptno dept.deptno%type;
cursor cemp(dno number) is select sal from emp where deptno=dno;
psal emp.sal%type;
count1 number;count2 number;count3 number;
salTotal number;
begin
open cdept;
loop
fetch cdept into pdeptno;
exit when cdept%notfound;
count1 :=0;count2 :=0;count3 :=0;
select sum(sal) into salTotal from emp where deptno=pdeptno;
open cemp(pdeptno);
loop
fetch cemp into psal;
exit when cemp%notfound;
if psal<3000 then count1 :=count1+1;
elsif psal>3000 and psal<6000 then count2 :=count2+1;
else count3 :=count3+1;
end if;
end loop;
close cemp;
insert into msg1 values(pdeptno,count1,count2,count3,nvl(salTotal,0));
end loop;
close cdept;
commit;
dbms_output.put_line(‘完成‘);
end;
/
create table msg1(
n1 number,
n2 number,
n3 number,
n4 number,
n5 number
)
select * from msg1;
-----被0除
set serveroutput on
declare
pnum number;
begin
pnum :=1/0;
exception
when Zero_Divide then dbms_output.put_line(‘1:0不能做被除数‘);
dbms_output.put_line(‘2:0不能做被除数‘);
when Value_error then dbms_output.put_line(‘算术或转换错误‘);
when others then dbms_output.put_line(‘其他例外‘);
end;
/
----循环
set serveroutput on
declare
pnum number;
begin
pnum :=0;
loop
exit when pnum>10;
dbms_output.put_line(pnum);
pnum :=pnum+1;
end loop;
end;
/
-----查询并打印7839的姓名和薪水
set serveroutput on
declare
pename emp.ename%type;
psal emp.sal%type;
begin
select ename,sal into pename,psal from emp where empno=7839;
dbms_output.put_line(pename||‘的薪水是‘||psal);
end;
/
------查询50号部门的员工
set serveroutput on
declare
cursor cemp is select ename from emp where deptno=30;
pename emp.ename%type;
no_emp_found exception;
begin
open cemp;
fetch cemp into pename;
if cemp%notfound then
raise no_emp_found;
end if;
close cemp;
exception
when no_emp_found then dbms_output.put_line(‘没有找到员工‘);
when others then dbms_output.put_line(‘其他例外‘);
end;
/
select * from emp;
/*
create [or replace] PROCEDURE 过程名(参数列表)
AS
PLSQL子程序体;
查询并返回某个员工的姓名 月薪和职位
思考: out参数太多???
*/
create or replace procedure queryEmpInfo(
eno in number,
pename out varchar2,
psal out number,
pjob out varchar2
)
as
begin
select ename,sal,empjob into pename,psal,pjob from emp where empno=eno;
end;
/
/*
实施复杂的安全性检查
禁止在非工作时间 往emp表中插入数据
CREATE [or REPLACE] TRIGGER 触发器名
{BEFORE | AFTER}
{DELETE | INSERT | UPDATE [OF 列名]}
ON 表名
PLSQL 块
周末:to_char(sysdate,‘day‘) in (‘星期六‘,‘星期日‘)
上班前 下班后: to_number(to_char(sysdate,‘hh24‘)) not between 9 and 18
*/
create or replace trigger securityEmp
before insert
on emp
begin
if to_char(sysdate,‘day‘) in (‘星期三‘,‘星期六‘) or
to_number(to_char(sysdate,‘hh24‘)) not between 9 and 18 then
raise_application_error(-20001,‘不能在非工作时间插入数据‘);
end if;
end;
/
select * from emp;
insert into emp(empno,ename,empjob,sal) values(100,‘hhh‘,‘manager‘,8000);
select * from user_source where name like ‘%SECURITYEMP%‘;
drop trigger checksal;
/*
数据确认
涨后的薪水不能少于涨前的薪水
CREATE [or REPLACE] TRIGGER 触发器名
{BEFORE | AFTER}
{DELETE | INSERT | UPDATE [OF 列名]}
ON 表名
[FOR EACH ROW [WHEN(条件) ] ]
PLSQL 块
*/
create or replace trigger checksal
before update
on emp
for each row
begin
if :new.sal<:old.sal then
raise_application_error(-20002,‘涨后的薪水不能少于涨前的薪水.涨前:‘||:old.sal||‘ 涨后:‘||:new.sal);
end if;
end;
/
update emp set sal=sal-100 where empno=7839;
/*
CREATE [OR REPLACE] FUNCTION 函数名(参数列表)
RETURN 函数值类型
AS
PLSQL子程序体;
查询某个员工的年收入
*/
create or replace function queryEmpIncome(eno in number)
return number
as
psal emp.sal%type;
pcomm emp.comm%type;
begin
select sal,comm into psal,pcomm from emp where empno=eno;
return psal*12+nvl(pcomm,0);
end;
/
/*
create [or replace] PROCEDURE 过程名(参数列表)
AS
PLSQL子程序体;
为指定的员工涨100块钱 并打印涨前和涨后的薪水
*/
create or replace procedure raiseSalary(
eno in number
)
as
psal emp.sal%type;
begin
select sal into psal from emp where empno=eno;
update emp set sal=sal+100 where empno=eno;
dbms_output.put_line(‘涨前:‘||psal||‘ 涨后:‘||(psal+100));
end;
/
create or replace trigger sayNewEmp
after insert on emp
declare
begin
dbms_output.put_line(‘插入数据!‘);
end;
/
delete from emp where empno=1000;
select * from emp;
select * from user_source where type=‘CURSOR‘;
/*
1.错误的删除了数据,并且已经提交
2.错误的删除了表drop table
3.如何获取表上的历史记录
4.如何撤销已经提交的事务
闪回的类型
1.闪回表:将表返回到过去的一个时间上
2.闪回删除:操作oracle的回收站
3.闪回版本查询:表上的历史记录
4.闪回事务查询:获取表上的一个UNDO_SQL
5.闪回数据库:将数据库返回到过去的一个时间上
6.闪回归档日志
*/
---查询没有提交的数据
show parameter undo;
----设置闪回时间 scope的取值:memoery(本次回话) spfile(重启后生效) both()
alter system set undo_retention=1200 scope=both;
---系统改变号SCN----6952590965600 6952590966674
select to_char(sysdate,‘yyyy-mm-dd hh24:mi:ss:mm‘) 时间,
timestamp_to_scn(sysdate) SCN
from dual;
---闪回表
create table flashback_table (fid number,fname varchar2(40));
insert into flashback_table values(1,‘tom‘);
insert into flashback_table values(2,‘marry‘);
insert into flashback_table values(3,‘mike‘);
delete from flashback_table where fid=2;
select * from flashback_table;
---启动行移动ALTER TABLE table_name ENABLE ROW MOVEMENT
alter table flashback_table enable row movement;
flashback table flashback_table to SCN 6952590966674;
---如何获取离操作最近的一个时间或者SCN?
select * from tab;
drop table EMP20 purge;
----闪回删除的表
flashback table MSG1 to before drop rename to msg5 ;
create table MSG1(mid number,mname varchar2(30));
select * from msg4;
show recyclebin;
purge recyclebin;
-------管理员没有回收站
create table ggg(mid number,mname varchar2(30));
insert into ggg values(1,‘ssss‘);
drop table ggg;
select * from ggg;
flashback table ggg to before drop ;
flashback table ggg to before drop rename to msg5 ;
select * from msg5;
-----返回版本
create table version_table(tid number,tname varchar2(30));
insert into version_table values(1,‘tom‘);
insert into version_table values(2,‘mary‘);
insert into version_table values(3,‘mike‘);
update version_table set tname=‘mary123‘ where tid=2;
select * from version_table;
-----查询返回版本的语法
select tid,tname,versions_operation,versions_starttime,versions_endtime,versions_xid from version_table versions between timestamp minvalue and maxvalue;
----闪回事务查询
create table tracation_table(tid number,tname varchar2(30));
insert into tracation_table values(1,‘tom‘);
insert into tracation_table values(2,‘mary‘);
insert into tracation_table values(3,‘mike‘);
update tracation_table set tname=‘dfdfd‘ where tid=2;
select tid,tname,versions_operation,versions_starttime,versions_endtime,versions_xid from tracation_table versions between timestamp minvalue and maxvalue;
select operation,undo_sql from flashback_transaction_query where xid=‘0B00080016DF0000‘;
exp scott/tiger @10.4.237.4:1521:orcl file=f:/a.dmp log=f:/log.log tables=dept,emp