-- 首先,以超级管理员的身份登陆oracle
sqlplus sys/bjsxt as sysdba
--而后,解除对scott用户的锁
alter user scott account unlock;
--那么这个用户名就能使用了。
--(默认全局数据库名orcl)
一、select ename, sal * 12 from emp; --计算年薪
二、select 2*3 from dual; --计算一个比较纯的数据用dual表
三、select sysdate from dual; --查看当前的系统时间
四、select ename, sal*12 anuual_sal from emp; --给搜索字段更更名称(双引号 keepFormat 别名有特殊字符,要加双引号)。
五、--任何含有空值的数学表达式,最后的计算结果都是空值。
六、select ename||sal from emp; --(将sal的查询结果转化为字符串,与ename链接到一块儿,至关于Java中的字符串链接)
七、select ename||'afasjkj' from emp; --字符串的链接
八、select distinct deptno from emp; --消除deptno字段重复的值
九、select distinct deptno , job from emp; --将与这两个字段都重复的值去掉
十、select * from emp where deptno=10; --(条件过滤查询)
十一、select * from emp where empno > 10; --大于 过滤判断
十二、select * from emp where empno <> 10 --不等于 过滤判断
1三、select * from emp where ename > 'cba'; --字符串比较,实际上比较的是每一个字符的AscII值,与在Java中字符串的比较是同样的
1四、select ename, sal from emp where sal between 800 and 1500; --(between and过滤,包含800 1500)
1五、select ename, sal, comm from emp where comm is null; --(选择comm字段为null的数据)
1六、select ename, sal, comm from emp where comm is not null; --(选择comm字段不为null的数据)
1七、select ename, sal, comm from emp where sal in (800, 1500,2000); --(in 表范围)
1八、select ename, sal, hiredate from emp where hiredate > '02-2月-1981'; --(只能按照规定的格式写)
1九、select ename, sal from emp where deptno =10 or sal >1000;
20、select ename, sal from emp where deptno =10 and sal >1000;
2一、select ename, sal, comm from emp where sal not in (800, 1500,2000); --(能够对in指定的条件进行取反)
2二、select ename from emp where ename like '%ALL%'; --(模糊查询)
2三、select ename from emp where ename like '_A%'; --(取第二个字母是A的全部字段)
2四、select ename from emp where ename like '%/%%'; --(用转义字符/查询字段中自己就带%字段的)
2五、select ename from emp where ename like '%$%%' escape '$'; --(用转义字符/查询字段中自己就带%字段的)
2六、select * from dept order by deptno desc; (使用order by desc字段 对数据进行降序排列 默认为升序asc);
2七、select * from dept where deptno <>10 order by deptno asc; --(咱们能够将过滤之后的数据再进行排序)
2八、select ename, sal, deptno from emp order by deptno asc, ename desc; --(按照多个字段排序 首先按照deptno升序排列,当detpno相同时,内部再按照ename的降序排列)
2九、select lower(ename) from emp; --(函数lower() 将ename搜索出来后所有转化为小写);
30、select ename from emp where lower(ename) like '_a%'; --(首先将所搜索字段转化为小写,而后判断第二个字母是否是a)
3一、select substr(ename, 2, 3) from emp; --(使用函数substr() 将搜素出来的ename字段从第二个字母开始截,一共截3个字符)
3二、select chr(65) from dual; --(函数chr() 将数字转化为AscII中相对应的字符)
3三、select ascii('A') from dual; --(函数ascii()与32中的chr()函数是相反的 将相应的字符转化为相应的Ascii编码) )
3四、select round(23.232) from dual; --(函数round() 进行四舍五入操做)
3五、select round(23.232, 2) from dual; --(四舍五入后保留的小数位数 0 个位 -1 十位)
3六、select to_char(sal, '$99,999.9999')from emp; --(加$符号加入千位分隔符,保留四位小数,没有的补零)
3七、select to_char(sal, 'L99,999.9999')from emp; --(L 将货币转化为本地币种此处将显示¥人民币)
3八、select to_char(sal, 'L00,000.0000')from emp; --(补零位数不同,可到数据库执行查看)
3九、select to_char(hiredate, 'yyyy-MM-DD HH:MI:SS') from emp; --(改变日期默认的显示格式)
40、select to_char(sysdate, 'yyyy-MM-DD HH:MI:SS') from dual; --(用12小时制显示当前的系统时间)
4一、select to_char(sysdate, 'yyyy-MM-DD HH24:MI:SS') from dual; --(用24小时制显示当前的系统时间)
4二、select ename, hiredate from emp where hiredate > to_date('1981-2-20 12:24:45','YYYY-MM-DD HH24:MI:SS'); --(函数to-date 查询公司在所给时间之后入职的人员)
4三、select sal from emp where sal > to_number('$1,250.00', '$9,999.99'); --(函数to_number()求出这种薪水里带有特殊符号的)
4四、select ename, sal*12 + nvl(comm,0) from emp; --(函数nvl() 求出员工的"年薪 + 提成(或奖金)问题")
4五、select max(sal) from emp; -- (函数max() 求出emp表中sal字段的最大值)
4六、select min(sal) from emp; -- (函数max() 求出emp表中sal字段的最小值)
4七、select avg(sal) from emp; --(avg()求平均薪水);
4八、select to_char(avg(sal), '999999.99') from emp; --(将求出来的平均薪水只保留2位小数)
4九、select round(avg(sal), 2) from emp; --(将平均薪水四舍五入到小数点后2位)
50、select sum(sal) from emp; --(求出每月要支付的总薪水)
------------------------/组函数(共5个):将多个条件组合到一块儿最后只产生一个数据------min() max() avg() sum() count()----------------------------/
5一、select count(*) from emp; --求出表中一共有多少条记录
5二、select count(*) from emp where deptno=10; --再要求一共有多少条记录的时候,还能够在后面跟上限定条件
5三、select count(distinct deptno) from emp; --统计部门编号前提是去掉重复的值
------------------------聚组函数group by() --------------------------------------
5四、select deptno, avg(sal) from emp group by deptno; --按照deptno分组,查看每一个部门的平均工资
5五、select max(sal) from emp group by deptno, job; --分组的时候,还能够按照多个字段进行分组,两个字段不相同的为一组
5六、select ename from emp where sal = (select max(sal) from emp); --求出
5七、select deptno, max(sal) from emp group by deptno; --搜素这个部门中薪水最高的的值
--------------------------------------------------having函数对于group by函数的过滤 不能用where--------------------------------------
5八、select deptno, avg(sal) from emp group by deptno having avg(sal) >2000; (order by )--求出每一个部门的平均值,而且要 > 2000
5九、select avg(sal) from emp where sal >1200 group by deptno having avg(sal) >1500 order by avg(sal) desc;--求出sal>1200的平均值按照deptno分组,平均值要>1500最后按照sal的倒序排列
60、select ename,sal from emp where sal > (select avg(sal) from emp); --求那些人的薪水是在平均薪水之上的。
6一、select ename, sal from emp join (select max(sal) max_sal ,deptno from emp group by deptno) t on (emp.sal = t.max_sal and emp.deptno=t.deptno); --查询每一个部门中工资最高的那我的
------------------------------/等值链接--------------------------------------
6二、select e1.ename, e2.ename from emp e1, emp e2 where e1.mgr = e2.empno; --自链接,把一张表当成两张表来用
6三、select ename, dname from emp, dept; --92年语法 两张表的链接 笛卡尔积。
6四、select ename, dname from emp cross join dept; --99年语法 两张表的链接用cross join
6五、select ename, dname from emp, dept where emp.deptno = dept.deptno; -- 92年语法 表链接 + 条件链接
6六、select ename, dname from emp join dept on(emp.deptno = dept.deptno); -- 新语法
6七、select ename,dname from emp join dept using(deptno); --与66题的写法是同样的,可是不推荐使用using : 假设条件太多
--------------------------------------/非等值链接------------------------------------------/
6八、select ename,grade from emp e join salgrade s on(e.sal between s.losal and s.hisal); --两张表的链接 此种写法比用where更清晰
6九、select ename, dname, grade from emp e
join dept d on(e.deptno = d.deptno)
join salgrade s on (e.sal between s.losal and s.hisal)
where ename not like '_A%'; --三张表的链接
70、select e1.ename, e2.ename from emp e1 join emp e2 on(e1.mgr = e2.empno); --自链接第二种写法,同62
7一、select e1.ename, e2.ename from emp e1 left join emp e2 on(e1.mgr = e2.empno); --左外链接 把左边没有知足条件的数据也取出来
7二、select ename, dname from emp e right join dept d on(e.deptno = d.deptno); --右外链接
7三、select deptno, avg_sal, grade from (select deptno, avg(sal) avg_sal from emp group by deptno) t join salgrade s on (t.avg_sal between s.losal and s.hisal);--求每一个部门平均薪水的等级
7四、select ename from emp where empno in (select mgr from emp); -- 在表中搜索那些人是经理
7五、select sal from emp where sal not in(select distinct e1.sal from emp e1 join emp e2 on(e1.sal < e2.sal)); -- 面试题 不用组函数max()求薪水的最大值
7六、select deptno, max_sal from
(select avg(sal) max_sal,deptno from emp group by deptno)
where max_sal =
(select max(max_sal) from
(select avg(sal) max_sal,deptno from emp group by deptno)
);--求平均薪水最高的部门名称和编号。
7七、select t1.deptno, grade, avg_sal from
(select deptno, grade, avg_sal from
(select deptno, avg(sal) avg_sal from emp group by deptno) t
join salgrade s on(t.avg_sal between s.losal and s.hisal)
) t1
join dept on (t1.deptno = dept.deptno)
where t1.grade =
(
select min(grade) from
(select deptno, grade, avg_sal from
(select deptno, avg(sal) avg_sal from emp group by deptno) t
join salgrade s on(t.avg_sal between s.losal and s.hisal)
)
)--求平均薪水等级最低的部门的名称 哈哈 确实比较麻烦
7八、create view v$_dept_avg_sal_info as
select deptno, grade, avg_sal from
(select deptno, avg(sal) avg_sal from emp group by deptno) t
join salgrade s on(t.avg_sal between s.losal and s.hisal);
--视图的建立,通常以v$开头,但不是固定的
7九、select t1.deptno, grade, avg_sal from v$_dept_avg_sal_info t1
join dept on (t1.deptno = dept.deptno)
where t1.grade =
(
select min(grade) from
v$_dept_avg_sal_info t1
)
)--求平均薪水等级最低的部门的名称 用视图,能简单一些,至关于Java中方法的封装
80、---建立视图出现权限不足时候的解决办法:
conn sys/admin as sysdba;
--显示:链接成功 Connected
grant create table, create view to scott;
-- 显示: 受权成功 Grant succeeded
8一、-------求比普通员工最高薪水还要高的经理人的名称 -------
select ename, sal from emp where empno in
(select distinct mgr from emp where mgr is not null)
and sal >
(
select max(sal) from emp where empno not in
(select distinct mgr from emp where mgr is not null)
)
8二、---面试题:比较效率
select * from emp where deptno = 10 and ename like '%A%';--好,将过滤力度大的放在前面
select * from emp where ename like '%A%' and deptno = 10;
8三、-----表的备份
create table dept2 as select * from dept;
8四、-----插入数据
insert into dept2 values(50,'game','beijing');
----只对某个字段插入数据
insert into dept2(deptno,dname) values(60,'game2');
8五、-----将一个表中的数据彻底插入另外一个表中(表结构必须同样)
insert into dept2 select * from dept;
8六、-----求前五名员工的编号和名称(使用虚字段rownum 只能使用 < 或 = 要使用 > 必须使用子查询)
select empno,ename from emp where rownum <= 5;
8六、----求10名雇员之后的雇员名称--------
select ename from (select rownum r,ename from emp) where r > 10;
8七、----求薪水最高的前5我的的薪水和名字---------
select ename, sal from (select ename, sal from emp order by sal desc) where rownum <=5;
8八、----求按薪水倒序排列后的第6名到第10名的员工的名字和薪水--------
select ename, sal from
(select ename, sal, rownum r from
(select ename, sal from emp order by sal desc)
)
where r>=6 and r<=10
8九、----------------建立新用户---------------
一、backup scott--备份
exp--导出
二、create user
create user guohailong identified(认证) by guohailong default tablespace users quota(配额) 10M on users
grant create session(给它登陆到服务器的权限),create table, create view to guohailong
三、import data
imp
90、-----------事务回退语句--------
rollback;
9一、-----------事务确认语句--------
commit;--此时再执行rollback无效
9二、--当正常断开链接的时候例如exit,事务自动提交。 当非正常断开链接,例如直接关闭dos窗口或关机,事务自动提交
9三、/*有3个表S,C,SC
S(SNO,SNAME)表明(学号,姓名)
C(CNO,CNAME,CTEACHER)表明(课号,课名,教师)
SC(SNO,CNO,SCGRADE)表明(学号,课号成绩)
问题:
1,找出没选过“黎明”老师的全部学生姓名。
2,列出2门以上(含2门)不及格学生姓名及平均成绩。
3,即学过1号课程有学过2号课全部学生的姓名。
*/答案:
一、
select sname from s join sc on(s.sno = sc.sno) join c on (sc.cno = c.cno) where cteacher <> '黎明';
二、
select sname where sno in (select sno from sc where scgrade < 60 group by sno having count(*) >=2);
三、
select sname from s where sno in (select sno, from sc where cno=1 and cno in
(select distinct sno from sc where cno = 2);
)
9四、--------------建立表--------------
create table stu
(
id number(6),
name varchar2(20) constraint stu_name_mm not null,
sex number(1),
age number(3),
sdate date,
grade number(2) default 1,
class number(4),
email varchar2(50) unique
);
9五、--------------给name字段加入 非空 约束,并给约束一个名字,若不取,系统默认取一个-------------
create table stu
(
id number(6),
name varchar2(20) constraint stu_name_mm not null,
sex number(1),
age number(3),
sdate date,
grade number(2) default 1,
class number(4),
email varchar2(50)
);
9六、--------------给nameemail字段加入 惟一 约束 两个 null值 不为重复-------------
create table stu
(
id number(6),
name varchar2(20) constraint stu_name_mm not null,
sex number(1),
age number(3),
sdate date,
grade number(2) default 1,
class number(4),
email varchar2(50) unique
);
9七、--------------两个字段的组合不能重复 约束:表级约束-------------
create table stu
(
id number(6),
name varchar2(20) constraint stu_name_mm not null,
sex number(1),
age number(3),
sdate date,
grade number(2) default 1,
class number(4),
email varchar2(50),
constraint stu_name_email_uni unique(email, name)
);
9八、--------------主键约束-------------
create table stu
(
id number(6),
name varchar2(20) constraint stu_name_mm not null,
sex number(1),
age number(3),
sdate date,
grade number(2) default 1,
class number(4),
email varchar2(50),
constraint stu_id_pk primary key (id),
constraint stu_name_email_uni unique(email, name)
);
9九、--------------外键约束 被参考字段必须是主键 -------------
create table stu
(
id number(6),
name varchar2(20) constraint stu_name_mm not null,
sex number(1),
age number(3),
sdate date,
grade number(2) default 1,
class number(4) references class(id),
email varchar2(50),
constraint stu_class_fk foreign key (class) references class(id),
constraint stu_id_pk primary key (id),
constraint stu_name_email_uni unique(email, name)
);
create table class
(
id number(4) primary key,
name varchar2(20) not null
);
100、---------------修改表结构,添加字段------------------
alter table stu add(addr varchar2(29));
10一、---------------删除字段--------------------------
alter table stu drop (addr);
10二、---------------修改表字段的长度------------------
alter table stu modify (addr varchar2(50));--更改后的长度必需要能容纳原先的数据
10三、----------------删除约束条件----------------
alter table stu drop constraint 约束名
10四、-----------修改表结构添加约束条件---------------
alter table stu add constraint stu_class_fk foreign key (class) references class (id);
10五、---------------数据字典表----------------
desc dictionary;
--数据字典表共有两个字段 table_name comments
--table_name主要存放数据字典表的名字
--comments主要是对这张数据字典表的描述
10五、---------------查看当前用户下面全部的表、视图、约束-----数据字典表user_tables---
select table_name from user_tables;
select view_name from user_views;
select constraint_name from user-constraints;
10六、-------------索引------------------
create index idx_stu_email on stu (email);-- 在stu这张表的email字段上创建一个索引:idx_stu_email
10七、---------- 删除索引 ------------------
drop index index_stu_email;
10八、---------查看全部的索引----------------
select index_name from user_indexes;
10九、---------建立视图-------------------
create view v$stu as selesct id,name,age from stu;
视图的做用: 简化查询 保护咱们的一些私有数据,经过视图也能够用来更新数据,可是咱们通常不这么用 缺点:要对视图进行维护
1十、-----------建立序列------------
create sequence seq;--建立序列
select seq.nextval from dual;-- 查看seq序列的下一个值
drop sequence seq;--删除序列
1十一、------------数据库的三范式--------------
(1)、要有主键,列不可分
(2)、不能存在部分依赖:当有多个字段联合起来做为主键的时候,不是主键的字段不能部分依赖于主键中的某个字段
(3)、不能存在传递依赖
==============================================PL/SQL==========================
1十二、-------------------在客户端输出helloworld-------------------------------
set serveroutput on;--默认是off,设成on是让Oracle能够在客户端输出数据
11三、begin
dbms_output.put_line('helloworld');
end;
/
11四、----------------pl/sql变量的赋值与输出----
declare
v_name varchar2(20);--声明变量v_name变量的声明以v_开头
begin
v_name := 'myname';
dbms_output.put_line(v_name);
end;
/
11五、-----------pl/sql对于异常的处理(除数为0)-------------
declare
v_num number := 0;
begin
v_num := 2/v_num;
dbms_output.put_line(v_num);
exception
when others then
dbms_output.put_line('error');
end;
/
11六、----------变量的声明----------
binary_integer:整数,主要用来计数而不是用来表示字段类型 比number效率高
number:数字类型
char:定长字符串
varchar2:变长字符串
date:日期
long:字符串,最长2GB
boolean:布尔类型,能够取值true,false,null--最好给一初值
11七、----------变量的声明,使用 '%type'属性
declare
v_empno number(4);
v_empno2 emp.empno%type;
v_empno3 v_empno2%type;
begin
dbms_output.put_line('Test');
end;
/
--使用%type属性,能够使变量的声明根据表字段的类型自动变换,省去了维护的麻烦,并且%type属性,能够用于变量身上
11八、---------------Table变量类型(table表示的是一个数组)-------------------
declare
type type_table_emp_empno is table of emp.empno%type index by binary_integer;
v_empnos type_table type_table_empno;
begin
v_empnos(0) := 7345;
v_empnos(-1) :=9999;
dbms_output.put_line(v_empnos(-1));
end;
11九、-----------------Record变量类型
declare
type type_record_dept is record
(
deptno dept.deptno%type,
dname dept.dname%type,
loc dept.loc%type
);
begin
v_temp.deptno:=50;
v_temp.dname:='aaaa';
v_temp.loc:='bj';
dbms_output.put_line(v temp.deptno || ' ' || v temp.dname);
end;
120、-----------使用 %rowtype声明record变量
declare
v_temp dept%rowtype;
begin
v_temp.deptno:=50;
v_temp.dname:='aaaa';
v_temp.loc:='bj';
dbms_output.put_line(v temp.deptno || '' || v temp.dname)
end;
12一、--------------sql%count 统计上一条sql语句更新的记录条数
12二、--------------sql语句的运用
declare
v_ename emp.ename%type;
v_sal emp.sal%type;
begin
select ename,sal into v_ename,v_sal from emp where empno = 7369;
dbms_output.put_line(v_ename || '' || v_sal);
end;
12三、 -------- pl/sql语句的应用
declare
v_emp emp%rowtype;
begin
select * into v_emp from emp where empno=7369;
dbms_output_line(v_emp.ename);
end;
12四、-------------pl/sql语句的应用
declare
v_deptno dept.deptno%type := 50;
v_dname dept.dname%type :='aaa';
v_loc dept.loc%type := 'bj';
begin
insert into dept2 values(v_deptno,v_dname,v_loc);
commit;
end;
12五、-----------------ddl语言,数据定义语言
begin
execute immediate 'create table T (nnn varchar(30) default ''a'')';
end;
12六、------------------if else的运用
declare
v_sal emp.sal%type;
begin
select sal into v_sal from emp where empno = 7369;
if(v_sal < 2000) then
dbms_output.put_line('low');
elsif(v_sal > 2000) then
dbms_output.put_line('middle');
else
dbms_output.put_line('height');
end if;
end;
12七、-------------------循环 =====do while
declare
i binary_integer := 1;
begin
loop
dbms_output.put_line(i);
i := i + 1;
exit when (i>=11);
end loop;
end;
12八、---------------------while
declare
j binary_integer := 1;
begin
while j < 11 loop
dbms_output.put_line(j);
j:=j+1;
end loop;
end;
12九、---------------------for
begin
for k in 1..10 loop
dbms_output.put_line(k);
end loop;
for k in reverse 1..10 loop
dbms_output.put_line(k);
end loop;
end;
130、-----------------------异常(1)
declare
v_temp number(4);
begin
select empno into v_temp from emp where empno = 10;
exception
when too_many_rows then
dbms_output.put_line('太多记录了');
when others then
dbms_output.put_line('error');
end;
13一、-----------------------异常(2)
declare
v_temp number(4);
begin
select empno into v_temp from emp where empno = 2222;
exception
when no_data_found then
dbms_output.put_line('太多记录了');
end;
13二、----------------------建立序列
create sequence seq_errorlog_id start with 1 increment by 1;
13三、-----------------------错误处理(用表记录:将系统日志存到数据库便于之后查看)
-- 建立日志表:
create table errorlog
(
id number primary key,
errcode number,
errmsg varchar2(1024),
errdate date
);
declare
v_deptno dept.deptno%type := 10;
v_errcode number;
v_errmsg varchar2(1024);
begin
delete from dept where deptno = v_deptno;
commit;
exception
when others then
rollback;
v_errcode := SQLCODE;
v_errmsg := SQLERRM;
insert into errorlog values (seq_errorlog_id.nextval, v_errcode,v_errmsg, sysdate);
commit;
end;
133---------------------PL/SQL中的重点cursor(游标)和指针的概念差很少
declare
cursor c is
select * from emp; --此处的语句不会马上执行,而是当下面的open c的时候,才会真正执行
v_emp c%rowtype;
begin
open c;
fetch c into v_emp;
dbms_output.put_line(v_emp.ename); --这样会只输出一条数据 134将使用循环的方法输出每一条记录
close c;
end;
134----------------------使用do while 循环遍历游标中的每个数据
declare
cursor c is
select * from emp;
v_emp c%rowtype;
begin
open c;
loop
fetch c into v_emp;
(1) exit when (c%notfound); --notfound是oracle中的关键字,做用是判断是否还有下一条数据
(2) dbms_output.put_line(v_emp.ename); --(1)(2)的顺序不能颠倒,最后一条数据,不会出错,会把最后一条数据,再次的打印一遍
end loop;
close c;
end;
135------------------------while循环,遍历游标
declare
cursor c is
select * from emp;
v_emp emp%rowtype;
begin
open c;
fetch c into v_emp;
while(c%found) loop
dbms_output.put_line(v_emp.ename);
fetch c into v_emp;
end loop;
close c;
end;
136--------------------------for 循环,遍历游标
declare
cursor c is
select * from emp;
begin
for v_emp in c loop
dbms_output.put_line(v_emp.ename);
end loop;
end;
137---------------------------带参数的游标
declare
cursor c(v_deptno emp.deptno%type, v_job emp.job%type)
is
select ename, sal from emp where deptno=v_deptno and job=v_job;
--v_temp c%rowtype;此处不用声明变量类型
begin
for v_temp in c(30, 'click') loop
dbms_output.put_line(v_temp.ename);
end loop;
end;
138-----------------------------可更新的游标
declare
cursor c --有点小错误
is
select * from emp2 for update;
-v_temp c%rowtype;
begin
for v_temp in c loop
if(v_temp.sal < 2000) then
update emp2 set sal = sal * 2 where current of c;
else if (v_temp.sal =5000) then
delete from emp2 where current of c;
end if;
end loop;
commit;
end;
139-----------------------------------procedure存储过程(带有名字的程序块)
create or replace procedure p
is--这两句除了替代declare,下面的语句所有都同样
cursor c is
select * from emp2 for update;
begin
for v_emp in c loop
if(v_emp.deptno = 10) then
update emp2 set sal = sal +10 where current of c;
else if(v_emp.deptno =20) then
update emp2 set sal = sal + 20 where current of c;
else
update emp2 set sal = sal + 50 where current of c;
end if;
end loop;
commit;
end;
--执行存储过程的两种方法:
(1)exec p;(p是存储过程的名称)
(2)
begin
p;
end;
/
140-------------------------------带参数的存储过程
create or replace procedure p
(v_a in number, v_b number, v_ret out number, v_temp in out number)
is
begin
if(v_a > v_b) then
v_ret := v_a;
else
v_ret := v_b;
end if;
v_temp := v_temp + 1;
end;
141----------------------调用140
declare
v_a number := 3;
v_b number := 4;
v_ret number;
v_temp number := 5;
begin
p(v_a, v_b, v_ret, v_temp);
dbms_output.put_line(v_ret);
dbms_output.put_line(v_temp);
end;
142------------------删除存储过程
drop procedure p;
143------------------------建立函数计算我的所得税
create or replace function sal_tax
(v_sal number)
return number
is
begin
if(v_sal < 2000) then
return 0.10;
elsif(v_sal <2750) then
return 0.15;
else
return 0.20;
end if;
end;
----144-------------------------建立触发器(trigger) 触发器不能单独的存在,必须依附在某一张表上
--建立触发器的依附表
create table emp2_log
(
ename varchar2(30) ,
eaction varchar2(20),
etime date
);
create or replace trigger trig
after insert or delete or update on emp2 ---for each row 加上此句,每更新一行,触发一次,不加入则值触发一次
begin
if inserting then
insert into emp2_log values(USER, 'insert', sysdate);
elsif updating then
insert into emp2_log values(USER, 'update', sysdate);
elsif deleting then
insert into emp2_log values(USER, 'delete', sysdate);
end if;
end;
145-------------------------------经过触发器更新数据
create or replace trigger trig
after update on dept
for each row
begin
update emp set deptno =:NEW.deptno where deptno =: OLD.deptno;
end;
------只编译不显示的解决办法 set serveroutput on;
145-------------------------------经过建立存储过程完成递归
create or replace procedure p(v_pid article.pid%type,v_level binary_integer) is
cursor c is select * from article where pid = v_pid;
v_preStr varchar2(1024) := '';
begin
for i in 0..v_leave loop
v_preStr := v_preStr || '****';
end loop;
for v_article in c loop
dbms_output.put_line(v_article.cont);
if(v_article.isleaf = 0) then
p(v_article.id);
end if;
end loop;
end;
146-------------------------------查看当前用户下有哪些表---
--首先,用这个用户登陆而后使用语句:
select * from tab;
147-----------------------------用Oracle进行分页!--------------
--由于Oracle中的隐含字段rownum不支持'>'因此:
select * from (
select rownum rn, t.* from (
select * from t_user where user_id <> 'root'
) t where rownum <6
) where rn >3
148------------------------Oracle下面的清屏命令----------------
clear screen; 或者 cle scr;
149-----------将建立好的guohailong的这个用户的密码改成abc--------------
alter user guohailong identified by abc
--当密码使用的是数字的时候可能会不行
--使用在10 Oracle以上的正则表达式在dual表查询
with test1 as(
select 'ao' name from dual union all
select 'yang' from dual union all
select 'feng' from dual )
select distinct regexp_replace(name,'[0-9]','') from test1
------------------------------------------
with tab as (
select 'hong' name from dual union all
select 'qi' name from dual union all
select 'gong' name from dual)
select translate(name,'\\0123456789','\\') from tab;
CREATE OR REPLACE PROCEDURE
calc(i_birth VARCHAR2) IS
s VARCHAR2(8);
o VARCHAR2(8);
PROCEDURE cc(num VARCHAR2, s OUT VARCHAR2) IS
BEGIN
FOR i
IN REVERSE 2 .. length(num) LOOP
s := s || substr(substr(num, i, 1) + substr(num, i - 1, 1), -1);
END LOOP;
SELECT REVERSE(s) INTO s FROM dual;
END;
BEGIN o := i_birth;
LOOP
cc(o, s);
o := s;
dbms_output.put_line(s);
EXIT WHEN length(o) < 2;
END LOOP;
END;
set serveroutput on;
exec calc('19880323');
----算命pl/sql
with t as
(select '19880323' x from dual)
select
case
when mod (i, 2) = 0 then '命好'
when i = 9 then '命运悲惨'
else '通常'
end result
from (select mod(sum((to_number(substr(x, level, 1)) +to_number(substr(x, -level, 1))) *
greatest(((level - 1) * 2 - 1) * 7, 1)),10) i from t connect by level <= 4);
--构造一个表,和emp表的部分字段相同,可是顺序不一样
SQL> create table t_emp as
2 select ename,empno,deptno,sal
3 from emp
4 where 1=0
5 /
Table created
--添加数据
SQL> insert into t_emp(ename,empno,deptno,sal)
2 select ename,empno,deptno,sal
3 from emp
4 where sal >= 2500
5 /
select * from tb_product where createdate>=to_date('2011-6-13','yyyy-MM-dd') and createdate<=to_date('2011-6-16','yyyy-MM-dd');
sysdate --获取当前系统的时间
to_date('','yyyy-mm-dd')
select * from tb_product where to_char(createdate,'yyyy-MM-dd')>='2011-6-13' and to_char(createdate,'yyyy-MM-dd')<='2011-6-16';
select * from tb_product where trunc(createdate)>=? and trunc(createdate)<=?
用trunc函数就能够了
</pre>
<p> </p>
<pre name="code" >第一次
一、Oracle安装及基本命令
1.一、Orace简介
Oracleso一个生产中间件和数据库的较大生产商。其发展依靠了IBM公司。创始人是Larry Ellison。
1.二、Oracle的安装
1) Oracle的主要版本
Oracle 8;
Oracle 8i;i,指的是Internet
Oracle 9i;相比Oracle8i比较相似
Oracle 10g;g,表示网格技术
所谓网格技术,拿百度搜索为例,如今咱们须要搜索一款叫作“EditPlus”的文本编辑器软件,当咱们在百度搜索框中输入“EditPlus”进行搜索时, 会获得百度为咱们搜索到的大量关于它的连接,此时,咱们考虑一个问题,若是在我所处的网络环境周边的某个地方的服务器就提供这款软件的下载(也就是说提供一个下载连接供咱们下载),那么,咱们就不必去访问一个远在地球对面的某个角落的服务器去下载这款软件。如此一来就能够节省大量的网络资源。使用网格技术就能解决这种问题。咱们将整个网络划分为若干个网格,也就是说每个使用网络的用户,均存在于某一个网格,当咱们须要搜索指定资源时,首先在咱们所处的网格中查找是否存在指定资源,没有的话就扩大搜索范围,到更大的网格中进行查找,直到查找到为止。
2) 安装Oracle的准备工做
关闭防火墙,以避免影响数据库的正常安装。
3) 安装Oralce的注意事项
为了后期的开发和学习,咱们将全部数据库默认帐户的口令设置为统一口令的,方便管理和使用。
在点击“安装”后,数据库相关参数设置完成,其安装工做正式开始,在完成安装时,不要急着去点击“肯定”按钮,这时候,咱们须要进行一个很是重要的操做——帐户解锁。由于在Oracle中默认有一个叫作scott的帐户,该帐户中默认有4张表,而且存有相应的数据,因此,为了方便咱们学习Oracle数据库,咱们能够充分利用scott这个内置帐户。可是奇怪的是,在安装Oracle数据库的时候,scott默认是锁住的,因此在使用该帐户以前,咱们就须要对其进行解锁操做。在安装完成界面中,点击“口令管理”进入到相应的口令管理界面,找到scott帐户,将是否解锁一栏的去掉,便可完成解锁操做,后期就能够正常使用scott帐户。咱们运行SQLPlus(Oracle提供的命令行操做),会提示咱们输入用户名,如今咱们能够输入用户名scott,回车后,会提示输入口令,奇怪的是,当咱们输入在安装时设置的统一口令时,提示登陆拒绝,显然是密码错误,那么,在Oracle数据库中,scott的默认密码是tiger,因此使用tiger能够正常登陆,可是提示咱们scott的当前密码已经失效,让咱们从新设置密码,建议仍是设置为tiger。
在Oracle中内置了不少帐户,那么,咱们来了解下一下几个比较重要的内置帐户:
|-普通用户:scott/tiger
|-普通管理员:system/manager
|-超级管理员:sys/change_on_install
4) 关于Oracle的服务
在Oracle安装完成以后,会在咱们的系统中进行相关服务的注册,在全部注册的服务中,咱们须要关注一下两个服务,在实际使用Oracle的过程当中,这两个服务必须启动才能使Oracle正常使用。
|-第一个是OracleOraDb11g_home1TNSListener,监听服务,若是客户端想要链接数据库,此服务必须开启。
|-第二个是OracleServiceORCL,数据库的主服务。命名规则:OracleService + 数据库名称,此 服务必须启动。
此后,咱们能够经过命令行方式进入到SQLPlus的控制中心,进行命令的输入。
1.三、SQLPlus
SQLPlus是Oracle提供的一种命令行执行的工具软件,安装以后会自动在系统中进行注册。链接到数据库以后,就能够开始对数据库中的表进行操做了。
1) 对SQLPlus的环境设置
set linesize 长度;--设置每行显示的长度
set pagesize 行数;--修改每页显示记录的长度。
须要注意的是,上述连个参数的设置只在当前的命令行有效,命令行窗口重启或者开启了第二个窗口须要从新设置。
2) SQLPlus经常使用操做
在SQLPlus中输入ed a.sql,会弹出找不到文件的提示框,此时点击“是”,将建立一个a.sql文件,并弹出文本编辑页面,在这里能够输入相关的sql语句,编辑完成后保存,在命令行中经过 @ a.sql的方式执行命令,若是建立的文件后缀为“sql”,那么在执行的时候能够省略掉,便可以这么写, @ a。除了建立不存在的文件外,sqlplus中也能够经过指定本地存在的文件进行命令的执行,方式为 @ 文件路径。
在SQLPlus中能够经过命令使用其余帐户进行数据库的链接,如,当前链接的用户是scott,咱们须要使用sys进行链接,则能够这么操做:conn sys/430583 as sysdba,这里须要说明的是,sys是超级管理员,当咱们须要使用sys进行登陆的时候,那么须要额外的加上as sysdba表示sys将以管理员的身份登陆。这里有几点能够测试下
|-当咱们使用sys以sysdba的角色登陆时,其密码能够随意输入,不必定是咱们设置的统一口令(430583)。因此,咱们得出结论,在管理员登陆时,只对用户进行验证,而普通用户登陆时,执行用户和密码验证。
在sys帐户下访问scott下的emp表时,会提示错误,由于在sys中是不存在emp表的,那么若是须要在sys下访问scott的表(也就是说须要在a用户下访问b用户下的表),该如何操做呢?首先,咱们应该知道每一个对象是属于一种模式(模式是对用户所建立的数据库对象的总称,包括表,视图,索引,同义词,序列,过程和程序包等)的,而每一个帐户对应一个模式,因此咱们须要在sys下访问scott的表时,须要指明所访问的表是属于哪个模式的,即,咱们能够这样操做来实现上面的操做:select * from scott.emp;
若是咱们须要知道当前链接数据库的帐户是谁,能够这样操做:show user;
咱们知道,一个数据库能够存储多张表,那么,如何查看指定数据库的全部表名称呢?select * from tab;
在开发过程当中,咱们须要常常的查看某张表的表结构,这个操做能够这样实现:desc emp;
在SQLPlus中,咱们能够输入“/”来快速执行上一条语句。例如,在命令行中咱们执行了一条这样的语句:select * from emp;可是咱们须要再次执行该查询,就能够输入一个“/”就可快速执行。
3) 经常使用数据类型
number(4)-->表示数字,长度为4
varchar2(10)-->表示的是字符串,只能容纳10个长度
date-->表示日期
number(7,2)-->表示数字,小数占2位,整数占5位,总共7位
第二次
一、SQL语句
1.1 准备工做--熟悉scott帐户下的四张表及表结构
第一张表emp-->雇员表,用于存储雇员信息
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-->部门表,用于存储部门信息
deptno number(2) 部门编号
dname varchar2(14) 部门名称
loc varchar2(13) 部门位置
第三张表salgrade-->工资等级表,用于存储工资等级
grade number 等级名称
losal number 此等级的最低工资
hisal number 此等级的最高工资
第四张表bonus-->奖金表,用于存储一个雇员的工资及奖金
ename varchar2(10) 雇员姓名
job varchar2(9) 雇员工做
sal number 雇员工资
comm number 雇员奖金
1.二、SQL简介
什么是SQL?
SQL(Structured Query Language,结构查询语言)是一个功能强大的数据语言。SQL一般用于与数据库的通信。SQL是关系数据库管理系统的标准语言。SQL功能强大,归纳起来,分为如下几组:
|-DML-->Data Manipulation Language,数据操纵语言,用于检索或者修改数据,即主要是对数据库表中的数据的操做。
|-DDL-->Data Definition Language,数据定义语言,用于定义数据的结构,如建立、修改或者删除数据库对象,即主要是对表的操做。
|-DCL-->Data Control Language,数据控制语言,用于定义数据库用户的权限,即主要对用户权限的操做。
1.三、简单查询语句
简单查询语句的语法格式是怎样的?
select * |具体的列名 [as] [别名] from 表名称;
须要说明的是,在实际开发中,最好不要使用*代替须要查询的全部列,最好养成显式书写须要查询的列名,方便后期的维护;在给查询的列名设置别名的时候,能够使用关键字as,固然不用也是能够的。
拿emp表为例,咱们如今须要查询出雇员的编号、姓名、工做三个列的信息的话,就须要在查询的时候明确指定查询的列名称,即
select empno,ename,job from emp;
若是须要指定查询的返回列的名称,即给查询列起别名,咱们能够这样操做
select empno 编号,ename 姓名,job 工做 from emp;--省略as关键字的写法
或者
select empno as 编号,ename as 姓名,job as 作工 from emp; --保留as关键字的写法
若是如今须要咱们查询出emp中全部的job,咱们可能这么操做
select job from emp;
可能加上一个别名会比较好
select job 工做 from emp;
可是如今出现了一个问题,从查询的结果中能够看出,job的值是有重复的,这是为何呢?由于咱们知道一个job职位可能会对应多个雇员,好比,在一个公司的市场部会有多名市场人员,在这里咱们使用select job from emp;查询的其实是当前每一个雇员对应的工做职位,有多少
个雇员,就会对应的查询出多少个职位出来,因此就出现了重复值,为了消除这样的重复值,咱们在这里能够使用关键字distinct,接下来咱们继续完成上面的操做,即
select distinct job from emp;
因此,咱们能够看到,使用distinct的语法是这样的:
select distinct *|具体的列名 别名 from 表名称;
可是在消除重复列的时候,须要强调的是,若是咱们使用distinct同时查询多列时,则必须保证查询的全部列都存在重复数据才能消除掉。也就是说,当咱们须要查询a,b,c三列时,若是a表存在重复值,可是b和c中没有重复值,当使用distinct时是看不到消除重复列的效果的。拿scott中的emp表为例,咱们须要查询出雇员编号及雇员工做两个列的值,咱们知道一个工做会对应多个雇员,因此,在这种操做中,雇员编号是没有重复值的,可是工做有重复值,因此,执行这次查询的结果将是获得每个雇员对应的工做名称,显然,distinct没起到做用。
如今咱们获得了一个新的需求,要求咱们按以下的方式进行查询:
编号是:7369的雇员,姓名是:SMITH,工做是:CLERK
那么,咱们该如何解决呢?在这里,咱们须要使用到Oracle 中的字符串链接(“||”)操做来实现。若是须要显示一些额外信息的话,咱们须要使用单引号将要显示的信息包含起来。那么,上面的操做能够按照下面的方式进行,
select '编号是' || empno || '的雇员,姓名是:' || ename || ',工做是:' || job from emp;
下面咱们再看一个新的应用。公司业绩很好,因此老板想加薪,全部员工的工资上调20%,该如何实现呢?难道在表中一个一个的修改工资列的值吗?很显然不是的,咱们能够经过使用四则运算来完成加薪的操做。
select ename,sal*1.2 newsal from emp;--newsal是为上调后的工资设置的列名
四则运算,+、-、*、/,一样有优先顺序,先乘除后加减。
1.四、限定查询(where子句)
在前面咱们都是将一张表的所有列或者指定列的全部数据查询出来,如今咱们有新的需求了,须要在指定条件下查询出数据,好比,须要咱们查询出部门号为20的全部雇员、查询出工资在3000以上的雇员信息......,这些所谓的查询限定条件就是经过where来指定的。咱们先看看如何经过限定查询的方式进行相关操做。咱们在前面知道了简单的查询语法是:
select *|具体的列名 from 表名称;
那么,限定查询的语法格式以下:
select *|具体的列名 from 表名称 where 条件表达式;
首先,咱们如今要查询出工资在1500(不包括1500)之上的雇员信息
select * from emp where sal>1500;
下面的操做是查询出能够获得奖金的雇员信息(也就是奖金列不为空的记录)
select * from emp where comm is not null;
很显然,查询没有奖金的操做就是
select * from emp where comm is null;
咱们来点复杂的查询,查询出工资在1500之上,而且能够拿到奖金的雇员信息。这里的限定条件再也不是一个了,当全部的限定条件须要同时知足时,咱们采用and关键字将多个限定条件进行链接,表示全部的限定条件都须要知足,因此,该查询能够这么进行:
select * from emp where sal>1500 and comm is not null;
如今的需求发生了变化,要求查询出工资在1500之上,或者能够领取到奖金的雇员信息。这里的限定条件也是两个,可是有所不一样的是,咱们不须要同时知足着两个条件,由于需求中写的是
“或者”,因此在查询时,只须要知足两个条件中的一个就行。那么,咱们使用关键字or来实现“或者”的功能。
select * from emp where sal>1500 or comm is not null;
需求再次发生变化,查询出工资不大于1500(小于或等于1500),同时不能够领取奖金的雇员信息,可想这些雇员的工资必定不怎么高。以前咱们使用not关键字对限定条件进行了取反,那么,这里就至关于对限定条件总体取反。咱们分析下,工资不大于1500同时不能够领取奖金的反面含义就是工资大于1500同时能够领取奖金,因此,咱们这样操做:
select * from emp where sal>1500 and comm is not null;
这是原始需求取反后的查询语句,那么为了达到最终的查询效果,咱们将限定条件总体取反,即
select * from emp where not(sal>1500 and comm is not null);
在这里,咱们经过括号将一系列限定条件包含起来表示一个总体的限定条件。
咱们在数学中学过这样的表达式:100<a<200,那么在数据库中如何实现呢?同样的,咱们如今要查询出工资在1500之上,可是在3000之下的所有雇员信息,很显然,两个限定条件,同时要知足才行。
select * from emp where sal>1500 and sal<3000;
这里不要异想天开的写成select * from emp where 1500<sal<3000;()试试吧,绝对会报错。 很简单,数据库软件不支持这样的写法,至少如今的数据库没有谁去支持这样的写法。
在SQL语法中,提供了一种专门指定范围查询的过滤语句:between x and y,至关于a>=x and a<=y,也就是包含了等于的功能,其语法格式以下:
select * from emp where sal between 1500 and 3000;
如今咱们使用这种范围查询的方式修改上面的语句以下:
select * from emp where sal between 1500 and 3000;
好了,咱们如今开始使用数据库中很是重要的一种数据类型,日期型。
查询出在1981年雇佣的所有雇员信息,看似很简单的一个查询操做,这样写吗?
select * from emp where hiredate=1981;()
很显然,有错。hiredate是date类型的,1981看似是一个年份(日期),可是像这样使用,它仅仅是一个数字而已,类型都匹配,怎么进行相等判断呢?继续考虑。咱们先这样操做,查询emp表的全部信息,
select * from emp;
从查询结果中,咱们重点关注hiredate这一列的数据格式是怎么定义的,
20-2月 -81,很显然,咱们抽象的表示出来是这样的,
一个月的第几天-几月 -年份的后两位
因此,接下来咱们就有思路了,咱们就按照这样的日期格式进行限定条件的设置,该如何设置呢?考虑下,查询1981年雇佣的雇员,是否是这个意思,从1981年1月1日到1981年12月31日雇佣的就是咱们须要的数据呢?因此,这样操做吧
select * from emp where hiredate between '1-1月 -81' and '31-12月 -81';
能够看到,上面的限定条件使用了单引号包含,咱们暂且能够将一个日期看作是一个字符串。由上面的范例中咱们获得结论:between...and ...除了能够进行数字范围的查询,还能够进行日期范围的查询。
咱们再来看下面的例子,查询出姓名是smith的雇员信息,嗯,很简单,这样操做
select * from emp where ename='smith';
看似没有问题,限定条件也给了,单引号也没有少,但是为何查询不到记录呢?明明记得emp表中有一个叫作smith的雇员呀?难道被删掉了,好吧,咱们不须要在这里耗费时间猜想语句自身的问题了,上面的语句在语法上没有任何问题,咱们先看看emp表中有哪些雇员,
select * from emp;
能够看到,确实有一个叫作smith的雇员,可是不是smith,而是SMITH,因此,咱们忽略了一个很重要的问题,Oracle是对大小写敏感的。因此,更改以下:
select * from emp where ename='SMITH';
如今看一个这样的例子,要求查询出雇员编号是7369,7499,7521的雇员信息。若是按照之前的作法,是这样操做的,
select * from emp where empno=7369 or empno=7499 or empno=7521;
执行一下吧,确实没任何问题,查询出指定雇员编号的全部信息。可是SQL语法提供一种更好的解决方法,使用in关键字完成上面的查询,以下:
select * from emp where empno in(7369,7499,7521);
总结下in的语法以下:
select * from tablename where 列名 in (值1,值2,值3);
select * from tablename where 列名 not in (值1,值2,值3);
须要说明的是,in关键字不光能够用在数字上,也能够用在字符串的信息上。看下面的例子
查询出姓名是SMITH、ALLEN、KING的雇员信息
select * from emp where ename in('SMITH','ALLEN','KING');
若是在指定的查询范围中附加了额外的内容,不会影响查询结果。
模糊查询对于提升用户体验是很是好的,对于数据库的模糊查询,咱们经过like关键字来实现。首先咱们了解下like主要使用的两种通配符:
|-“%”-->能够匹配任意长度的内容,包括0个字符;
|-“_”-->能够匹配一个长度的内容。
下面咱们看这样一个需求,查询全部雇员姓名中第二个字母包含“M”的雇员信息
select * from emp where ename like '_M%';
说明下,前面的“_”匹配姓名中第一个字母(任意一个字母),“%”匹配M后面出现的0个或者多个字母。
查询出雇员姓名中包含字母M的雇员信息。分析可知,字母M能够出如今姓名的任意位置,如何进行正确的匹配呢?
select * from emp where ename like '%M%';
这里仍是使用%,匹配0个或者多个字母,便可以表示M出如今姓名的任意位置上。
若是咱们在使用like查询的时候没有指定查询的关键字,则表示查询内容,即
select * from emp where ename like '%%';
至关于咱们前面看到的
select * from emp;
前面咱们遇到了一个这样的需求,查询出在1981年雇佣的全部雇员信息,当时咱们采起的是使用范围查询between ... and ...实现的,如今咱们使用like一样能够实现
select * from emp where hiredate like '%81%';
查询工资中包含6的雇员信息
select * from emp where sal like '%5%';
在操做条件中还能够使用:>、>=、=、<、<=等计算符号
对于不等于符号,有两种方式:<>、!=
如今须要咱们查询雇员编号不是7369的雇员信息
select * from emp where empno<>7369;
select * from emp where empno!=7369;
1.五、对查询结果进行排序(order by子句)
在查询的时候,咱们经常须要对查询结果进行一种排序,以方便咱们查看数据,好比以雇员编号排序,以雇员工资排序等。排序的语法是:
select *|具体的列名称 from 表名称 where 条件表达式 order by 排序列1,排序列2 asc|desc;
asc表示升序,默认排序方式,desc表示降序。
如今要求全部的雇员信息按照工资由低到高的顺序排列
select * from emp order by sal;
在升级开发中,会遇到多列排序的问题,那么,此时,会给order by指定多个排序列。要求查询出10部门的全部雇员信息,查询的信息按照工资由高到低排序,若是工资相等,则按照雇佣日期由早到晚排序。
select * from emp where deptno=10 order by sal desc,hiredate asc;
须要注意的是,排序操做是放在整个SQL语句的最后执行。
1.六、单行函数
在众多的数据库系统中,每一个数据库之间惟一不一样的最大区别就在于函数的支持上,使用函数能够完成一系列的操做功能。单行函数语法以下:
function_name(column|expression,[arg1,arg2...])
参数说明:
function_name:函数名称
columne:数据库表的列名称
expression:字符串或计算表达式
arg1,arg2:在函数中使用参数
单行函数的分类:
字符函数:接收字符输入而且返回字符或数值
数值函数:接收数值输入并返回数值
日期函数:对日期型数据进行操做
转换函数:从一种数据类型转换到另外一种数据类型
通用函数:nvl函数,decode函数
字符函数:
专门处理字符的,例如能够将大写字符变为小写,求出字符的长度。
如今咱们看一个例子,将小写字母转为大写字母
select upper('smith') from dual;
在实际中,咱们会遇到这样的状况,用户须要查询smith雇员的信息,可是咱们数据库表中存放的是SMITH,这时为了方便用户的使用咱们将用户输入的雇员姓名字符串转为大写,
select * from emp where ename=upper('smith');
一样,咱们也能够使用lower()函数将一个字符串变为小写字母表示,
select lower('HELLO WORLD') from dual;
那么,将字符串的首字母变为大写该如何实现呢?咱们使用initcap()函数来完成上面的操做。
select initcap('HELLO WOLRD') from dual;
在前面的学习中咱们知道,在scot帐户下的emp表中的雇员姓名采用全大写显示,如今咱们须要激昂姓名的首字母变为大写,该如何操做呢?
select initcap(ename) from emp;
咱们在前面使用了字符串链接操做符“||”对字符串链接显示,好比:
select '编号为' || empno || '的姓名是:' || ename from emp;
那么,在字符函数中提供concat()函数实现链接操做。
select concat('hello','world') from dual;
上面的范例使用函数实现以下:
select concat('编号为',empno,'的姓名是:',ename);?????????
此种方式不如链接符“||”好使。
在字符函数中能够进行字符串的截取、求出字符串的长度、进行指定内容的替换
select substr('hello',1,3) 截取字符串,length('hello') 字符串长度,replace('hello','l','x') 字符串替换 from dual;
经过上面范例的操做,咱们须要注意几如下:
Oralce中substr()函数的截取点是从0开始仍是从1开始;针对这个问题,咱们来操做看下,将上面的截取语句改成:
select substr('hello',0,3) 截取字符串 from dual;
由查询结果能够发现,结果同样,也就是说从0和从1的效果是彻底同样,这归咎于Oracle的智能化。
若是如今要求显示全部雇员的姓名及姓名的后三个字符,咱们知道,每一个雇员姓名的字符串长度可能不一样,因此咱们采起的措施是求出整个字符串的长度在减去2,咱们这样操做,
select ename,substr(ename,length(ename)-2) from emp;
虽然功能实现了,可是有没有羽化的方案呢?固然是有的,咱们分析下,当咱们在截取字符串的时候,给定一个负数值是什么效果,对,就是倒着截取,咱们采起这种方式优化以下:
select ename,substr(ename,-3) from emp;
数值函数:
四舍五入:round()
截断小数位:trunc()
取余(取模):mod()
执行四舍五入操做,能够指定保留的小数位
select round(789.536) from dual;
select round(789.436) from dual;
select round(789.436,2) from dual;
能够直接对整数进行四舍五入的进位
select round(789.536,-3) from dual;--1000
select round(789.536,-2) from dual;--800
trunc()函数与round()函数的不一样在于,trunc不会保留任何的小数位,并且小数点也不会执行四舍五入的操做,也就是说在使用trunc()函数时,它会将数值从小数点截断,只保留整数部分。
select trunc(789.536) from dual;--789
固然使用trunc()函数也能够设置小数位的保留位数
select trunc(789.536,2) from dual;--789.53
select trunc(789.536,-2) from dual;--700
使用mod()函数能够进行取余的操做
select mod(10,3) from dual;--1
日期函数:
在Oracle中提供了不少余日期相关的函数,包括加减日期等。可是在日期进行加或者减结果的时候有一些规律:
日期-数字=日期
日期+数字=日期
日期-日期=数字(天数的差值)
显示部门10的孤雁进入公司的星期数,要想完成此查询,必须知道当前的日期,在Oralce中能够经过如下的操做求出当前日期,使用sysdate表示
select sysdate from dual;
如何求出星期数呢?使用公式:当前日期-雇佣日期=天数 / 7 = 星期数,因此
select empno,ename,round((sysdate-hiredate)/7) from emp;
在Oracle中提供了如下的日期函数支持:
months_between()-->求出给定日期范围的月数
add_months()-->在指定日期上加上指定的月数,求出以后的日期
next_day()-->下一个的今天是哪个日期
last_day()-->求出给定日期的最后一天日期
查询出全部雇员的编号,姓名,和入职的月数
select empno,ename,round(months_between(sysdate,hiredate)) from emp;
查询出当前日期加上4个月后的日期
select add_months(sysdate,4) from dual;
查询出下一个给定日期数
select next_day(sysdate,'星期一') from dual;
查询给定日期的最后一天,也就是给定日期的月份的最后一天
select last_day(sysdate) from dual;
转换函数:
to_char()-->转换成字符串
to_number()-->转换成数字
to_date()-->转换成日期
咱们先看看前面作的一个范例,查询全部雇员的雇员编号,姓名和雇佣时间
select empno,ename,hiredate from emp;
可是如今的要求是讲年、月、日进行拆分,此时咱们就须要使用to_char()函数进行拆分,拆分的时候必须指定拆分的通配符:
年-->y,年是四位数字,因此使用yyyy表示
月-->m,月是两位数字,因此使用mm表示
日-->d,日是两位数字,因此使用dd表示
select empno,ename,to_char(hiredate,'yyyy') year,to_char(hiredate,'mm') month,to_char(hiredate,'dd') day from emp;
咱们还能够使用to_char()进行日期显示的转换功能,Oracle中默认的日期格式是:19-4月 -87,而中国喜欢的格式是:1987-04-19
select empno,ename,to_char(hiredate,'yyyy-mm-dd') from emp;
从显示结果中咱们能够看到,对于月份和日的显示中,若是不足10,就会自动补零,哪一个0咱们成为前导0,若是不但愿显示前导0的话,则能够使用fm去掉
select empno,ename,to_char(hiredate,'fmyyyy-mm-dd') from emp;
固然,to_char()也能够用在数字上
查询所有的雇员编号、姓名和工资
select empno,ename,sal from emp;
咱们能够看到,当工资数比较大时,是不利于读的,那么,咱们能够在数字中使用“,”每3位进行一个分隔,此时,就能够使用to_char()进行格式化。格式化时,9并不表明实际的数字9,而是一个占位符
select empno,ename,to_char(sal,'99,999') from emp;
还有一个问题,工资数表示的是美圆仍是人民币呢?如何解决显示区域的问题呢?咱们能够使用下面的两种符号:
L-->表示Local的缩写,以本地的语言进行金额的显示
$-->表示美圆
select empno,ename,to_char(sal,'$99,999') from emp;
to_number()是能够讲字符串变为数字的函数
select to_number('123') + to_number('123') from dual;
to_date()能够讲一个字符串变为date的数据
select to_date('2012-09-12','yyyy-mm-dd') from dual;
通用函数:
如今又这样一个需求,求出每一个雇员的年薪。咱们知道求年薪的话应该加上奖金的,格式为(sal+comm)*12
select empno,ename,(sal+comm)*12 from emp;
查看结果,能够发现一个很奇怪的显现,居然有的雇员年薪为空,这是如何引发的呢?咱们分析下,首先能够查看下全部雇员的奖金列数据,发现只有部分雇员才能够领取奖金,没有领取奖金
的雇员其comm列是空的,没有任何值(null),由此,上面的四则运算显然没结果。为了解决这个问题,咱们须要用到一个通用函数nvl,将一个指定的null值变为指定的内容
select empno,ename,(sal+nvl(comm,0))*12 from emp;
decode()函数,此函数相似于if...elseif...else语句
其语法格式为:
decode(col/expression,search1,result1[search2,result2,......][,default])
说明:col/expression-->列名或表达式
search1.search2......-->为用于比较的条件
result一、result2......-->为返回值
若是col/expression和search i 相比较,相同的话返回result i ,若是没有与col/expression相匹配的结果,则返回默认值default。
select decode(1,1,'内容是1',2,'内容是2',3,'内容是3') from dual;
那么,如何在对表查询时使用decode()函数呢?咱们来定义一个需求,
如今雇员的工做职位有:
CLERK-->业务员
SALESMAN-->销售人员
MANAGER-->经理
ANALYST-->分析员
PRESIDENT-->总裁
要求咱们查询出雇员的编号,姓名,雇佣日期及工做,将工做替换为上面的中文
select empno 雇员编号,ename 雇员姓名,hiredate 雇佣日期,decode(job,'CLERK','业务员','SALESMAN','销售人员','MANAGER','经理','ANALYST','分析员','PRESIDENT','总裁') 职位 from emp;
从查询结果能够看出,全部的职位都被相应的中文替换了。
1.七、SQL语法练习
如今咱们再次经过相应的练习对scott帐户下的四张表作进一步的熟悉。
选择部门30中的全部员工。
select * from emp where deptno=30;
此查询包含一个限定条件
列出全部业务员的姓名,编号和部门编号。
select empno 编号,ename 姓名,deptno 部门编号 from emp where job='CLERK';
此查询应用了别名,单个限定条件,须要注意的是Oracle是区分大小写的,因此咱们要将业务员大写为“CLERK”才能查询出数据,或者使用upper()函数。
select empno 编号,ename 姓名,deptno 部门编号 from emp where job=upper('clerk');
找出佣金高于工资的雇员信息
select * from emp where comm>sal;
此查询为单个限定条件的查询
找出佣金高于工资的60%的雇员信息
select * from emp where comm>sal*0.6;
此查询使用了比较运算符和四则运算符
找出部门10中全部经理和部门20中全部业务员的详细信息。
select * from emp where (deptno=10 and job='MANAGER') or (deptno=20 and job='CLERK');
此查询使用了多限定查询,逻辑运算符and 和 or ,而且使用()将多个限定条件包含做为一个总体看待。
看一个比较复杂的需求。找出部门10中全部经理,部门20中全部业务员,既不是经理又不是业务员可是工资大于或等于2000的全部雇员信息。
select * from emp where (deptno=10 and job='MANAGER') or (deptno=20 and job='CLERK') or (sal>=2000 and job not in('MANAGER','CLERK'));
找出领取佣金的雇员的不用工做。这个需求包含的信息有,工做会重复复,因此咱们须要使用关键字distinct消除重复的记录,可以领取佣金说明comm is not null
select distinct job from emp where comm is not null;
找出不能领取佣金或者领取的佣金低于100的雇员信息
select * from emp where comm is null or comm<100;
找出每月中倒数第三天雇佣的雇员信息,咱们分析下,Oracle为咱们提供了一个叫作last_day()的函数,它的功能是查询出指定日期的最后一天对应的日期,可是咱们这里是要查询倒数第三天,如何处理?咱们按照倒序的思想,将最后一天减去2不就获得了倒数第三天吗?
select * from emp where last_day(hiredate)-2=hiredate;
来一个颇有趣的需求,找出早于12年前雇佣的雇员信息,咱们将这个需求转变下,咱们知道Oracle中有一个函数叫作months_between(),它的做用是查询出给定的日期的差值,这个差值是月份数,因此,咱们这么考虑
select * from emp where months_between(sysdate,hiredate)/12>12;
看一个字符函数的应用。以首字母大写的方式显示全部雇员的姓名
select initcap(ename) from emp;
显示雇员姓名长度正好是5的雇员姓名
select ename from emp where length(ename)=5;
显示雇员姓名中不含“R”的雇员姓名
select ename from emp where ename not like '%R%';
此查询使用了like语句作模糊查询,当like后指定的关键字为“%%”时,表示查询出全部数据
显示全部雇员姓名的前三个字符
select substr(ename,0,3) from emp;
select substr(ename,1,3) from emp;
此处应该强调的是,截取点的指定中,0和1的效果是同样的。
显示全部雇员的姓名,而且用“a”替换全部的“A”
select ename,replace(ename,'A','a') from emp;
此处要强调的是replace()函数的参数中,第一个表示须要作替换操做的列名称,第二个参数是新的字符串,第三个参数表示的是原始的字符串,也就是须要替换的字符串。
显示工龄为10或以上的雇员姓名和雇佣日期
select ename,hiredate from emp where months_between(sysdate,hiredate)/12>10;
显示雇员的详细信息,并按照姓名排序
select * from emp order by ename;
显示雇员的姓名和雇佣时间,根据其工龄,将最老的雇员排在最前面
select ename,hiredate from emp order by hiredate;
显示全部雇员的姓名、工做和工资,按照工做降序排列,若工做相同则按照工资排序
select ename,job,sal from emp order by job desc,sal;
显示全部雇员的姓名、雇佣的年份,月份,按照雇佣日期所在月排序,若是月份相同则将最先的年份的雇员排在最前面。此需求首先要求出全部雇员的雇佣月份,使用to_char()函数求出月份
select ename,to_char(hiredate,'mm') month,to_char(hiredate,'yyyy') year from emp order by month,year;
显示在一个月为30天的状况下全部雇员的日薪,忽略余数。忽略余数使用round()函数完成
select ename,round(sal/30) from emp;
找出在每一年2月份雇员的全部雇员信息
select * from emp where to_char(hiredate,'mm')=2;
此处仍是使用了to_char()函数求出月份
对于每一个雇员,显示其到今天为止的总天数
select ename,round(sysdate-hiredate) from emp;
显示雇员姓名中包含“A”的全部雇员姓名
select ename from emp where ename like '%A%';
以年月日的方式显示全部雇员的工龄。年,求出总月数/12,此时会产生小数,可是咱们不能再这里进行四舍五入,而是采用trunc()函数获得整数部分
select ename,trunc(months_between(sysdate,hiredate)/12) year from emp;
如今工龄的年获得了,下面求出月份,咱们知道年除完以后的余数就是月,使用取余函数进行处理
select ename ,trunc(months_between(sysdate,hiredate)/12) year,trunc(mod(months_between(sysdate,hiredate),12)) month from emp;
获得月份后,如何求出天数呢?咱们知道日期-日期获得的是天数(须要作取整处理),将总天数/30(假设每个月为30天)获得的就是剩余的天数值
select ename ,trunc(months_between(sysdate,hiredate)/12) year,trunc(mod(months_between(sysdate,hiredate),12)) month,trunc(mod(sysdate-hiredate,30)) day from emp;
这样就完成了上面的查询操做。
第三次
一、Oracle
1.一、多表查询
1) 多表查询的基本语法
前面的查询都是针对一张表的操做,若是在查询的时候涉及到多张表,那么就称为多表查询,夺标查询的语法以下:
select *|具体的列名 from 表名称1,表名称2 where 条件表达式 order by 排序字段 asc|desc;
下面看一个例子,对emp表和dept表进行查询
select * from emp,dept;
如此多的数据,咱们要向知道当前的记录总数,如何操做呢?
select count(*) from emp,dept;--56
select count(*) from emp;--14
select count(*) from emp;--4
此处查询使用count(*|具体的列名)查询总记录数
上面的三条查询语句分别获得了多表查询,单表查询的总记录数,很明显的看到,多表查询的记录数56并不等于单表查询的总记录数之和18,怎么回事呢?由于,在进行多表查询时,会产生笛卡尔积,若是表的数据越多,那么笛卡尔积就会越大。若是如今有5张表,每张表有10000条数据,查询5张表会产生10000的5次方条数据,因此在实际开发中多表查询不建议过多的使用。
要向去掉笛卡尔积,能够使用关联来实现。如今咱们知道emp表中有字段deptno,dept表中有字段deptno,emp.deptno=dept.deptno就是灌篮字段。在多表查询中加入where语句就能够消除笛卡尔积
select * from emp,dept where emp.deptno=dept.deptno;
此时查询的记录数为14条,可是若是表名过长的话,不方便咱们使用,因此通常咱们会为表名设置别名,
select * from emp e,dept d where e.deptno=d.deptno;
若是在进行多表查询时,最好为表名设置别名
要求查询出雇员的编号、雇员姓名、部门编号、部门名称及部门位置
select e.empno,e.ename,e.deptno,d.dname,d.loc from emp e,dept d where e.deptno=d.deptno;
要求查询出每一个雇员的姓名,工做,雇员的直接上级领导的姓名
select e.ename,e.job,m.ename from emp e,emp m where e.mgr=m.empno;
此处查询将emp表作自身的关联
继续扩展以前的程序,要求将雇员素在部门名称同时列出
select e.ename,e.job,m.ename,d.dname from emp e,emp m,dept d where e.mgr=m.empno and e.deptno=d.deptno;
查询出每一个雇员的姓名,工资,部门名称,工资等级,以及领导的姓名及工资所在公司的等级
先肯定工资等级表
select * from salgrade;
在查询出每一个雇员的姓名,工资,部门名称和工资等级
select e.ename,e.sal,d.dname,s.grade from emp e,dept d,salgrade s where e.deptno=d.deptno and e.sal between s.losal and s.hisal;
查询其领导的姓名及工资等级
select e.ename,e.sal,m.ename,decode(ms.grade,1,'第五等工资',2,'第四等工资',3,'第三等工资',4,'第二等工资',5,'第一等工资'),decode(s.grade,1,'第五等工资',2,'第四等工资',3,'第三等工资',4,'第二等工资',5,'第一等工资'),d.dname from emp e,emp m,dept d,salgrade s,salgrade ms where e.mgr=m.empno and m.sal between ms.losal and ms.hisal and e.deptno=d.deptno and e.sal between s.losal and s.hisal;
2) 左、右链接
如今咱们先查询下dept表中的数据
select * from dept;
能够看到,dept表中包含了4条记录,如今咱们将emp表和dept表关联查询,查询一下指定的字段
select e.empno,e.ename,d.deptno,d.dname,d.loc from emp e,dept d where e.deptno=d.deptno;
有查询结果能够看到,部门表中的部门号只出现了3个,由于在雇员表中没有指定40部门的雇员,可是咱们如今须要查看两张表关联后的完整信息,该如何进行呢?
select e.empno,e.ename,d.deptno,d.dname,d.loc from emp e,dept d where e.deptno(+)=d.deptno;
如今的结果中没有指定雇员的部门信息也显示出来了。这里咱们使用到了右链接。有以下规律:
(+)在=左边表示右链接,查询时以=右边的表做为标准
(+)在=右边表示左链接,查询时以=左边的表做为标准
在前面咱们有过以下操做:查询雇员的编号,姓名及其领导的编号、姓名
select e.empno,e.ename,m.ename from emp e,emp m where e.mgr=m.empno;
可是咱们仔细观察会发现,雇员名称为KING的雇员信息没有显示出来,咱们知道KING为president,没有领导,因此按照上面的方式是不能查询出来的,修改以下:
select e.empno,e.ename,m.ename from emp e,emp m where e.mgr=m.empno(+);
发如今加入作连接后KING出现了。
3) SQL:1999语法对SQL的支持
SQL:1999语法格式以下:
select table1.column,table2.column from table1
[cross join table2]|
[natural join table2]|
[join table2 using(column_name)]|
[join table2 on(table1.column_name=table2.column_name)]|
[left|right|full outer join table2 on(table1.column_name=table2.column_name)];
交叉链接(cross join):产生笛卡尔积
select * from emp cross join dept;--56
天然链接(natural join):自动进行关联字段的匹配
select * from emp natural join dept;
至关于
select * from emp,dept where emp.deptno=dept.deptno;
using子句:直接关联的操做列
select * from emp e join dept d using(deptno) where deptno=30;
on子句,用户本身编写链接的条件
select * from emp e join dept d on(e.deptno=d.deptno) where d.deptno=30;
左链接(左外链接)、右链接(右外链接):left join,right join
select e.ename,d.deptno,d.dname,d.loc from emp e right outer join dept d on(e.deptno=d.deptno);
1.二、组函数及分组统计
什么是分组?
举例吧,把全部男生分为一组,把全部女生分为一组。
若是想要求出每一组的平均身高,评价呢年龄等,就须要使用分组函数。
1) 组函数
在SQL中经常使用的组函数有如下几个:
count()-->求出所有的记录数
max()-->求出一组数据中的最大值
min()-->求出一组数据中的最小值
avg()-->求出平均值
sum()-->求和
count()函数:
如今咱们须要查询出emp中有多少个雇员
select count(*) from emp;--14
max()、min(),求最大最小值,通常是针对数字的应用
求出全部雇员的最低工资
select min(sal) from emp;
求出全部雇员的最高工资
select max(sal) from emp;
sum()、avg(),求和,求平均值
求出部门20中的总工资
select sum(sal) from emp where deptno=20;
求出全部雇员的平均工资
select avg(sal) from emp;
2) 分组统计
要想使用分组统计,则首先应该固定其语法,使用group by进行分组,此时SQL语法格式以下:
select *|具体的列
from 表名称1
where 条件表达式
group by 分组条件
order by 排序字段 asc|desc
求出每一个部门的雇员数量,这里须要按照部门编号划分,及按照deptno分组
select deptno,count(empno) from emp group by deptno;
求出每一个部门的平均工资
select deptno,avg(sal)
from emp
group by deptno;
如今,咱们观察下面的一行代码:
select deptno,count(empno) from emp;
以上代码不能正确执行,报错为:不是单组分组函数,为何呢?
若是程序中使用了分组函数,则有两种能够使用的状况:
1-程序中存在了group by,并指定了分组条件,这样能够将分组条件一块儿查询出来。
2-若是不使用分组的话,则只能单独的使用分组函数
在使用分组函数的时候,不能出现分组函数和分组条件以外的字段。
看下面的代码:
select deptno,empno,count(empno) from emp group by deptno;
程序会报错,提示empno不是group by表达式,由于在这里,咱们使用了组函数count(empno),group by deptno,根据先前的规则,empno的出现是不合法的。
按照部门分组,并显示部门的名称,及每一个部门的员工数
select d.dname,count(e.ename) from dept d,emp e where d.deptno=e.deptno group by d.dname;
要求显示出平均工资大于2000的部门编号和平均工资
select deptno,avg(sal) from emp where avg(sal)>2000 group by deptno;
程序报错,提示avg(sal)>2000处不容许使用分组函数。由于分组函数只能在分组中使用,不容许出如今where语句之中,那么若是如今假设要指定分组的条件,则只能经过第二种条件的指令,having,此时SQL语法格式为:
select * | 具体的列名
from 表名称
where 条件表达式
group by 分组条件
having 分组条件
order by 排序字段 asc|desc
因此,咱们使用having完成上面的操做
select deptno,avg(sal) from emp group by deptno having avg(sal)>2000;
下面咱们看一个这样的需求:显示非销售人员工做名称以及从事同一工做的雇员的月工资的总和,而且要知足从事同一工做的雇员的月工资合计大于5000,输出结果按照月工资的合计升序排列
·-首先咱们查询出所有的非销售人员,限定条件job<>'SALESMAN'
select * from emp where job<>'SALESMAN';
·-按照工做名称分组,而且求出每组的工资总和
select job,sum(sal) from emp
where job<>'SALESMAN'
group by job;
·-对分组的调价进行限制,工资总和大于5000
select job,sum(sal) from emp
where job<>'SALESMAN'
group by job
having sum(sal)>5000;
·-对查询结果按照月工资的合计升序排列
select job,sum(sal) from emp
where job<>'SALESMAN'
group by job
having sum(sal)>5000
order by sum(sal) asc;
下面咱们总结下分组的简单原则:
--只要一列上存在重复的内容才有可能考虑到分组
使用分组时的注意点:
--分组函数能够嵌套使用,可是在组函数嵌套使用的时候不能再出现分组条件的查询语句
例如,咱们要求求出平均工资最高的部门工资
select deptno,max(avg(sal)) from emp
group by deptno;
程序会报错,提示deptno不是单组分组函数
修改代码以下:
select max(avg(sal)) from emp
group by deptno;
1.三、子查询
子查询:在一个查询的内部还包括另一个查询,则此查询称为子查询,子查询的格式以下:
select * | 具体的列名称
from 表名称
where 条件表达式(
select * | 具体的列名称
from 表名称
where 条件表达式(
...
)
group by 分组条件
having 分组条件
order by 排序字段 asc|desc
)
group by 分组条件
having 分组条件
order by 排序字段 asc|desc
要求查询出比7654工资要高的所有雇员信息
·-首先要知道7654雇员的工资是多少
select sal from emp where empno=7654;
·-上面查询的结果做为最后查询的子查询结果,只要是其余的工资大于上面的查询结果,则表示符合条件。
select * from emp where sal>(select sal from emp where empno=7654);
应该要强调的是,全部的子查询语句必须在“()”中编写。
子查询在操做上分为三类:
单列子查询:返回的结果是某列的一个内容,出现的概率最高
单行子查询:返回多个列,有多是一条完整的记录
多行子查询:返回多条记录
要求查询出工资比7654高,同时与7788从事相同工做的所有雇员信息
·-查询出7654的工资
select sal from emp where empno=7654;
·-查询出7788的工做名称
select job from emp where empno=7788;
·-总和查找
select * from emp where sal>(select sal from emp where empno=7654) and job=(select job from emp where empno=7788);
要求查询出工资最低的雇员姓名,工做,工资
·-求出最低工资
select min(sal) from emp;
·-以最低工资为条件进一步查询
select ename,job,sal from emp
where sal=(select min(sal) from emp);
要求查询出:部门名称,部门的员工数,部门的平均工资,部门的最低收入的雇员姓名,此时,程序须要两张表关联:dept、emp
·-若是要想求出每一个部门的员工数,平均工资,要使用分组统计,这里咱们按照deptno进行分组
select deptno,count(empno),avg(sal) from emp
group by deptno;
·-可是咱们要查询的是部门的名称,因此这里须要与dept表进行关联
select d.dname,ed.c,ed.a
from dept d,
(select deptno,count(empno) c,avg(sal) a from emp
group by deptno) ed
where d.deptno=ed.deptno;
·-求出最低收入的雇员姓名
select d.dname,ed.c,ed.a,e.ename
from dept d,(select deptno,count(empno) c,avg(sal) a,min(sal) min from emp
group by deptno) ed,emp e
where d.deptno=ed.deptno and e.sal=ed.min;
可是此程序中有一个问题,若是一个部门中同时存在两个给你工资最低的雇员,则程序会出现错误。
在子查询中,存在如下三种查询的操做符号:
in、any、all
in操做符的做用是指定一个查询的范围
求出每一个部门的最低工资的雇员信息。
分析:每一个部门的最低工资,返回值确定是多个,因此此时能够使用in指定一个操做范围。
select * from emp
where sal in(select min(sal) from emp group by deptno);
any操做符的通常用法:=any(与in操做符的功能彻底同样)、>any(比里面最小的值要大)、<any(比里面最大的值要小)
select * from emp
where sal=any(select min(sal) from emp group by deptno);
all操做符的通常用法:>all(比最大值要大)、<all(比最小值要小)
select * from emp
where sal>all(select min(sal) from emp group by deptno);
对于子查询来说,还能够进行多列子查询,一个子查询中同时返回多个查询的列。
select * from emp
where (sal,nvl(comm,-1)) in(select sal,nvl(comm,-1) from emp where deptno=20);
1.四、数据库更新操做
数据库的主要操做分为两种:
--数据库的查询操做:select
--数据库的更新操做:insert、update、delete
此时,为了保存原始的emp表的信息,在进行增长、修改、删除操做以前,先将此表复制一份
create table myemp as select * from emp;
1) 添加数据
添加数据的语法是:
insert into 表名称[(字段名1,字段名2,......)] values(值1,值2,......);
为myemp表添加一条新的记录,按照标准的作法完成
insert into myemp(empno,ename,job,mgr,hiredate,sal,comm,deptno) values(7899,'张三','清洁工',7369,'14-2月 -1995',9000,300,40);
在添加数据时,须要强调的是:对于数字,不用加单引号,可是字符串必须加上单引号。能够使用简略写法,当咱们想所有的阻断插入数据时,能够不用指定须要插入数据的字段名,可是,咱们并不推荐这种写法,由于这样写的坏处在于,当咱们向部分字段插入数据时,须要和表的字段顺序一一对一个才能插入成功,而使用标准写法时,只须要指定的字段名和value中的值一一对应就能够完成插入操做。
插入部分数据,如今要求插入一个新的雇员,可是此雇员暂时没有领导,也没有奖金,也就是说,在插入数据的时候,mgr和comm字段的值要置空。
第一种作法:不明确写出要插入的字段名 ,没有数据的字段写成null
insert into myemp values(8889,'王五','清洁工',null,'14-2月 -1982',9000,null,40);
第二种作法:明确写出要插入的字段名
insert into myemp(empno,ename,job,hiredate,sal,deptno) values(8889,'王五','清洁工','14-2月 -1982',9000,40);
在上面的插入操做中,咱们应该发现了这么一个问题,插入的日期都是按照Oracle默认的日期格式进行书写的,可是,如今有一个“2009-01-19”这样格式的日期,该如何插入到数据库表中呢?咱们英爱还记得在前面学习单行函数的时候,介绍了一个叫作to_date()的函数,该函数的功能是将一个字符串类型的数据变为date类型的数据。
insert into myemp(empno,ename,job,hiredate,sal,deptno) values(8888,'赵六','保洁工',to_date('2009-01-19','yyyy-mm-dd'),9000,40);
2) 修改数据
在SQL语法中使用update语句就能够完成数据的修改功能,此语句的语法格式以下:
修改所有:update 表名称 set 要修改的字段=新值,要修改的字段=新值,......;
修改局部:update 表名称 set 要修改的字段=新值,要修改的字段=新值,...... where 修改条件;
可是,从通常的开发角度上讲,咱们都在修改数据时加上修改条件
如今将myemp表中的全部雇员的奖金修改成1000-->修改所有
update myemp set comm=1000;
将编号为7899的雇员的工资修改成5000-->指定了更新条件
update myemp set sal=5000 where empno=7899;
将编号为7899的雇员的领导取消
update myemp set mgr=null where empno=7899;
注意点:在进行数据库更新的操做时,必定要写上更新的条件,拒绝批量更新。
将736九、889九、7788的领导及奖金取消
update myemp set mgr=null,comm=null where empno in(7369,7788,8899);
3) 删除数据
在SQL语法中能够使用delete命令删除记录,语法格式以下:
删除所有:delete from 表名称;
删除局部:delete from 表名称 where 删除条件;
删除编号是7899的雇员信息
delete from myemp where empno=7899;
删除编号是8889,7889,8888的雇员信息
delete from myemp where empno in(8889,7889,8888);
删除掉所有领取奖金的雇员
delete from myemp where comm is not null;
删除表的所有内容,此时不须要指定删除条件
delete from myemp;
在实际开发中不建议使用所有删除,在执行删除命令的时候都要指定删除条件。
1.五、事务处理
建立一个只包含10部门雇员信息的临时表
create table emp10 as select * from emp where deptno=10;
删除emp10中7782的雇员信息
delete from emp10 where empno=7782;
当咱们再次查询emp10表的数据时,该数据确实删除了,接下来,咱们作以下操做,再次开启一个sqlplus窗口,再次查询emp10的数据,咱们发现雇员编号为7782的雇员信息仍然存在,这是为何?
这就是Oracle中事务处理的概念了。
事务处理:所谓事务处理就是保证数据的完整性,全部的操做要么同时成功,要么同时失败。
在Oracle中对于每个链接到数据库的窗口(sqlplus、sqlplusw)链接以后实际上都会与数据库创建一个session,即:每个链接到数据库上的用户表示建立了一个session。
一个session对数据库所作的修改,不会马上反映到数据库的真实数据之上,是容许回滚的,当一个session提交全部的操做以后,数据库才真正的作出了修改。
在数据库的操做中提供了如下两个主要命令完成事物的处理:
--提交事物:commit
--回滚事物:rollback
若是数据已经被提交了则确定没法回滚,因此,回滚只有在事物未被提交时才有效。
在Oracle中关于事物的处理上夜壶存在一种死锁的概念。
一个session若是更新了数据库中的记录,其余session是没法马上更新的,要等待对方提交以后才容许更新。
下面咱们来测试下Oracle的事务处理是如何进行的。
首先,咱们在窗口1中查询出emp10的数据
select * from emp10;
如今作一个更新的操做,将编号为7934的雇员的工资更改成3000
update emp10 set sal=3000 where empno=7934;
如今咱们再次查询emp10的数据,发现,编号为7934的雇员工资确实更改成3000来 ,可是咱们应该知道,对于这个更新操做,咱们是没有提交的,咱们如今再打开一个窗口,查询emp10的数据,发现编号为7934的雇员工资仍是1300,这就验证了咱们所说的“事物未提交”,接下来,咱们在窗口2中进行一个更新操做,将7839的奖金设置为10000
update emp10 set comm=10000 where empno=7839;
下面咱们在窗口1中提交事物
在窗口2中再次查询emp10的数据,更新成功。
在窗口2中提交事物
一样在窗口1中查询emp10的数据,更新成功。
1.六、查询练习
列出至少有一个员工的全部部门
select deptno ,count(empno) from emp
group by deptno;
此查询使用了组函数,分组,注意,若是不加分组,该程序会报错
列出部门人数大于1的全部部门编号
select deptno,count(empno) from emp
group by deptno having count(empno)>1;
这里没使用where设置查询限定条件,由于where子句中时不能出现函数的。
经过部门表,查询出部门的信息
select d.*,ed.cou from dept d,(select deptno,count(empno) cou from emp
group by deptno) ed
where d.deptno=ed.deptno;
列出工资比“SMITH”多的全部雇员。
--求出SMITH的工资
select sal from emp where ename='SMITH';
--将上面的结果做为查询条件,只要工资比上面的结果大的就是符合条件的
select * from emp where sal>(select sal from emp where ename='SMITH');
列出全部员工的姓名和其直接上司的姓名
--此程序属于自身关联查询,为了获得KING,咱们使用左链接查询,以等号左边的表为标准
select e.ename,m.ename from emp e,emp m
where e.mgr=m.empno(+);
列出雇佣日期早于其直接上级的全部雇员的编号、姓名和部门名称
--自身关联,查找mgr=empno的同时还要比较hiredate,咱们先查询编号和姓名
select e.empno,e.ename
from emp e,emp m
where e.mgr=m.empno and e.hiredate<m.hiredate;
--若是要加入部门名称,咱们须要加入dept表,作表关联查询
select e.empno,e.ename,d.dname
from emp e,emp m,dept d
where e.mgr=m.empno and e.hiredate<m.hiredate and e.deptno=d.deptno;
列出部门名称和这些部门的雇员信息,同时列出那些没有雇员的部门
--左右关联问题,以=右边的表为标准
select d.deptno,d.dname,e.empno,e.ename
from dept d,emp e
where d.deptno=e.deptno(+);
列出全部“CLERK”的姓名和其部门名称,部门的人数
--找出全部CLERK的姓名和部门编号
select ename,deptno from emp
where job='CLERK';
--要想查询部门名称,则必须使用dept表
select e.ename,d.dname from emp e,dept d
where job='CLERK' and e.deptno=d.deptno;
--部门人数要用到分组完成,一旦使用分组,确定是group by
select e.ename,d.dname,ed.cou
from emp e,dept d,(select deptno, count(empno) cou from emp group by deptno) ed
where job='CLERK' and e.deptno=d.deptno and ed.deptno=e.deptno;
列出最低工资大于1500的各类工做以及从事此工做的所有雇员人数
--按工做分组,分组条件是最低工资大于1500
select job,min(sal) from emp
group by job having min(sal)>1500;
--工做就出来了,以后再求所有的雇佣人数
select e.job,count(e.empno)
from emp e
where e.job in(
select job from emp
group by job having min(sal)>1500
)
group by e.job;
列出在部门“SALES”工做的员工姓名,假定不知道销售部的部门编号
--经过dept表查询出销售部的部门编号
select deptno from dept where dname='SALES';
--将上面的查询结果做为下一步查询的条件
select ename from emp
where deptno=(
select deptno from dept where dname='SALES'
);
列出工资高于公司平均工资的所愿雇员,所在部门,上级领导,公司的工资等级
--求出公司的平均工资
select avg(sal) from emp;
--列出工资高于平均工资的雇员信息
select * from emp where sal>(select avg(sal) from emp);
--与部门表关联,查出所在部门的信息
select e.*,d.dname,d.loc from emp e,dept d
where sal>(select avg(sal) from emp) and e.deptno=d.deptno;
--要想查出上级领导,须要和自身进行关联查询
select e.empno,e.ename,m.ename,m.empno,d.deptno,d.dname,d.loc
from emp e,dept d,emp m
where e.sal>(select avg(sal) from emp)
and e.deptno=d.deptno
and e.mgr=m.empno(+);
--与工资等级表关联,查出工资等级
select e.empno,e.ename,s.grade,m.ename,m.empno,d.deptno,d.dname,d.loc
from emp e,dept d,emp m,salgrade s
where e.sal>(select avg(sal) from emp)
and e.deptno=d.deptno
and e.mgr=m.empno(+)
and e.sal between s.losal and s.hisal;
列出与scott从事相同工做的全部雇员及部门名称
--找到scott的工做
select job from emp where ename='SCOTT';
--找到和上面查询工做相同的雇员
select * from emp where job=(select job from emp where ename='SCOTT');
--使用dept表查询出所在部门名称
select e.*,d.dname from emp e,dept d
where job=(select job from emp where ename='SCOTT')
and ename!='SCOTT'
and d.deptno=e.deptno;
列出工资等于部门30中雇员的工资的全部雇员姓名和工资
--查出部门30中雇员的工资
select sal from emp where deptno=30;
--找出工资等于上面结果的雇员姓名
select ename,sal from emp
where sal in(select sal from emp where deptno=30)
and deptno!=30;
列出工资高于在30部门工做的全部雇员的工资的雇员姓名和工资,部门名称
--在以前的程序上进行修改,使用>all,比最大的还要大
select ename,sal
from emp where sal>all(
select sal from emp where deptno=30
)
and deptno!=30;
--使用dept表,查询出部门名称
select e.ename,e.sal,d.dname from emp e,dept d
where sal>all(
select sal from emp where deptno=30
)
and e.deptno!=30
and e.deptno=d.deptno;
列出在每一个部门工做的雇员数量,平均工资和平均工龄
--求出每一个部门的雇员数量,按照部门名称分组
select d.dname,count(e.empno)
from emp e,dept d
where e.deptno=d.deptno
group by d.dname;
--求出每一个部门的平均工资和工龄
select d.dname,count(e.empno),avg(e.sal),avg(months_between(sysdate,hiredate)/12) 年
from emp e,dept d
where e.deptno=d.deptno
group by d.dname;
列出全部雇员的姓名、部门名称和工资
--直接两张表关联
select e.ename,e.sal,d.dname
from emp e,dept d
where e.deptno=d.deptno;
列出全部部门的详细信息和部门的人数
--列出每一个部门的雇员人数
select deptno,count(empno) cou
from emp
group by deptno;
--把以上的查询做为一张临时表
select d.*,ed.cou from dept d,
(select deptno dto,count(empno) cou from emp group by deptno ) ed
where d.deptno=ed.dto;
查询结果中没包含40部门,修改以下
select d.*,nvl(ed.cou,0) from dept d,
(select deptno dto,count(empno) cou from emp group by deptno ) ed
where d.deptno=ed.dto(+);
列出各类工做的最低工资及从事此工做的雇员姓名
--按照工做分组,使用min()求出最低工资
select job,min(sal) from emp group by job;
--按照工资查询出雇员的信息
select * from emp
where sal in(select min(sal) from emp group by job);
列出各个部门的MANAGER的最低工资
select deptno,min(sal)
from emp
where job='MANAGER'
group by deptno;
列出全部雇员的年薪,按照年薪从低到高排序
select ename,(sal+nvl(comm,0))*12 yearsal from emp order by yearsal asc;
查询某个雇员的上级主管,并求出这些主管中的薪水超过3000的
select distinct m.* from emp e,emp m
where e.mgr=m.empno and m.sal>3000;
求出部门名称中带“S”的部门雇员的工资合计和部门人数
--查询部门表的部门名称,使用模糊查询,来肯定部门的编号
select deptno from dept where dname like '%S%';
--查询出符合上述条件的雇员工资合计和部门人数
select deptno,sum(sal),count(empno) from emp
where deptno in(select deptno from dept where dname like '%S%')
group by deptno;
第四次
一、Oracle
1.一、 建立和管理表
1) 经常使用的数据类型
varchar\varchar2-->表示的是一个字符串,有长度限制,255,
number-->number(n):表示一个整数,数字的长度是n,能够使用int
number(m,n):表示一个小数,数字小数长度为n,整数长度为m-n,能够使用float
date-->表示日期的类型,日期要按照标准的日期格式进行存放
clob-->大对象,表示大文本数据,通常能够存放4G的文本
blob-->大对象,表示二进制数据,最大能够存放4G,如:电影,歌曲,图片
2) 表的创建
表的创建仍是按照标准的语法进行,可是在表的创建时有时候会指定约束,那么此处先给出一个创建表的简单语法。
create table 表名称(
字段名称1 字段类型 [default 默认值],
字段名称2 字段类型 [default 默认值],
....
字段名称n 字段类型 [default 默认值]
)
在前面咱们使用了一种这样的语法来建立表:
create table 表名称 as (子查询)--将子查询的结果做为一张表
若是如今子查询写的是:select * from emp;表示将表结构和表的内容一块儿复制
若是如今子查询写的是:select * from emp where 1=2;加入了一个永远都不会成立的条件,则此时表示咱们复制的只是表的结构,不复制表的内容
复制表结构:
create table temp as(select * from emp where 1=2);
3) 表的删除
表的删除语法以下:
drop table 表名称;
4) 表的修改
在SQL语法操做中,提供了alter指令,经过alter指令就能够增长新的列
为emp表添加一个address列
alter table emp add(address varchar2(200) default'暂无地址');
修改emp表中的ename,将长度改成50
alter table emp modify(ename varchar2(50));
5) 为表重命名
在Oracle中提供了rename命令,能够为表从新进行命名,可是此语句只能在Oracle中使用。语法格式以下:
rename 旧的表名称 to 新的表名称;
6) 截断表
若是如今咱们须要清空一张表的数据,可是同时不须要回滚,能够马上释放资源就须要使用截断表的语法:
truncate table 表名称;
思考下面的问题:如今有一张国家表,里面只有一个国家名称的字段,内容以下:“中国、美国、巴西、荷兰“,如今要求经过查询实现对战功能:
中国->美国
中国->巴西
中国->荷兰
美国->中国
美国->巴西
美国->荷兰
......
分析:本程序只能使用笛卡尔积完成
首先,创建一张表
create table national(
name varchar2(30)
)
向表中增长测试数据
insert into national(name) values('中国');
insert into national(name) values('美国');
insert into national(name) values('巴西');
insert into national(name) values('荷兰');
查询的时候表本身和本身关联
select n1.name,n2.name from national n1,national n2 where n1.name<>n2.name;
1.二、约束
在数据库表的开发中,余数是必不可少的支持。使用约束能够更好的保证数据库中的数据完整性。
数据库中的约束分类:
--在实际中,约束主要分为如下五种:
···主键约束primary key:主键表示是一个惟一的标识,自己是不能为空的
|-例如:身份证号是惟一的,不可重复,不可为空
···惟一约束unique:在一个表中只容许创建一个主键约束,而其余列若是不但愿出现重复值的话,则能够使用惟一约束。
···检查约束:检查一个列的内容是否合法
|-例如:年龄。只能在0~150之间
|-例如:性别,只能是男、女、中性
···非空约束:姓名这样的字段里面的内容就不能为空
···外键约束:在两张表中进行约束操做。
1) 主键约束(primary key)
主键约束通常都是使用在id上,并且自己已经默认了内容不能为空,主键约束能够再建表的时候指定
如今咱们创建一张person表,在pid上增长主键约束
drop table person;
create table person(
pid varchar2(18) primary key,
name varchar2(200),
age number(3),
birthday date,
sex varchar2(3) default '男'
)
如今咱们向表中插入数据
insert into person(pid,name,age,birthday,sex) values('1111111111111111','张三',30,to_date('1976-08-09','yyyy-mm-dd'),'女');
insert into person(pid,name,age,birthday,sex) values('1111111111111111','李四',30,to_date('1976-08-04','yyyy-mm-dd'),'男');
当插入第二条语句时,会提示:违反惟一约束,那么咱们将pid的值设置为null
insert into person(pid,name,age,birthday,sex) values(null,'李四',30,to_date('1976-08-04','yyyy-mm-dd'),'男');
一样会提示错误:没法将 NULL 插入 ("SCOTT"."PERSON"."PID"),以上的约束是系统自动分配好的约束名称,也能够经过constraint指定一个约束的名字,
将person表的pid指定名称
drop table person;
create table person(
pid varchar2(18),
name varchar2(200),
age number(3),
birthday date,
sex varchar2(3) default '男',
constraint person_pid_pk primary key(pid)
)
2) 非空约束(not null)
使用非空约束,表示一个字段的内容不容许为空,即:插入数据的时候必须插入内容
drop table person;
create table person(
pid varchar2(18),
name varchar2(200) not null,
age number(3) not null,
birthday date,
sex varchar2(3) default '男',
constraint person_pid_pk primary key(pid)
)
3) 惟一约束(unique)
表示一个字段中的内容是惟一的,其余列不容许重复。
假设:如今姓名不容许出现重名的状况
drop table person;
create table person(
pid varchar2(18),
name varchar2(200) unique not null,
age number(3) not null,
birthday date,
sex varchar2(3) default '男',
constraint person_pid_pk primary key(pid)
)
4) 检查约束(check)
使用检查约束来判断一个列中插入的内容是否合法,例如,年龄的取值范围,性别的取值范围
drop table person;
create table person(
pid varchar2(18),
name varchar2(200) unique not null,
age number(3) not null check(age between 0 and 150),
birthday date,
sex varchar2(3) default '男' check(sex in('男','女','中')),
constraint person_pid_pk primary key(pid)
)
5) 主-外键约束(foreign key)
以前的约束都是针对一张表的,那么主-外键约束是针对两张表的约束。为何须要主-外键约束呢?
要求完成一个程序,一本书只属于一我的
书自己应该是一张表,一本书中必然有一个字段表示属于某我的的
drop table person;
drop table book;
create table person(
pid varchar2(18),
name varchar2(200) not null,
age number(3) not null,
birthday date,
sex varchar2(3) default '男',
constraint person_pid_pk primary key(pid),
constraint person_name_uk unique(name),
constraint person_age_ck check(age between 0 and 150),
constraint person_sex_ck check(sex in('男','女','中'))
);
create table book(
bid number primary key not null,
bname varchar2(20),
bprice number(5,2),
pid varchar2(18)
);
insert into person(pid,name,age,birthday,sex) values('1111111111111111','张三',30,to_date('1976-08-09','yyyy-mm-dd'),'女');
insert into book(bid,bname,bprice,pid) values(1,'JAVA SE',89.9,'0000000000000');
在插入第二条数据前,咱们看看pid字段的值,很明显,在咱们的person表中不存在这样的person,那么, 这样的数据时不该该插入到数据库中的,为了解决这样的问题,咱们使用主-外键关联,关联以后字表的数据要跟随父表的数据内内容。
drop table person;
drop table book;
create table person(
pid varchar2(18),
name varchar2(200) not null,
age number(3) not null,
birthday date,
sex varchar2(3) default '男',
constraint person_pid_pk primary key(pid),
constraint person_name_uk unique(name),
constraint person_age_ck check(age between 0 and 150),
constraint person_sex_ck check(sex in('男','女','中'))
);
create table book(
bid number primary key not null,
bname varchar2(20),
bprice number(5,2),
pid varchar2(18),
constraint person_book_pid_fk foreign key(pid) references person(pid)
);
如今咱们再次执行数据的插入操做,此时系统提示:违反完整约束条件 (SCOTT.PERSON_BOOK_PID_FK) - 未找到父项关键字,根据上面的分析没咱们修改以下:
insert into book(bid,bname,bprice,pid) values(1,'JAVA SE',89.9,'1111111111111111');
此时插入数据成功。
在使用主-外键关联的时候有几点须要注意:
|-在子表中设置的外键在父表中必须是主键
|-删除时应该先删除子表,再删除父表
在主-外键关联中也能够使用级联删除
以现有数据库中的数据为例
delete from person where pid='1111111111111111';
要删除person表中编号为1111111111111111的人员,可是这我的在book表中存在一本书的记录。提示错误:违反完整约束条件 (SCOTT.PERSON_BOOK_PID_FK) - 已找到子记录,那么,若是想删除成功必须先删除book表中pid对应的记录,再删除此人的信息
若是咱们但愿一个表中的数据在删除时,能够自动删除掉其对应的子表记录,则能够使用级联删除来实现。
drop table person;
drop table book;
create table person(
pid varchar2(18),
name varchar2(200) not null,
age number(3) not null,
birthday date,
sex varchar2(3) default '男',
constraint person_pid_pk primary key(pid),
constraint person_name_uk unique(name),
constraint person_age_ck check(age between 0 and 150),
constraint person_sex_ck check(sex in('男','女','中'))
);
create table book(
bid number primary key not null,
bname varchar2(20),
bprice number(5,2),
pid varchar2(18),
constraint person_book_pid_fk foreign key(pid) references person(pid) on delete cascade
);
6) 修改约束
若是一张表已经创建完成,则能够为其添加约束
关于约束类型的命名,必定要统一:
--primary key-->主键字段_pk
--unique-->字段_uk
--check-->字段_ck
--foreign key-->父字段_子字段_fk
为person添加一个约束
alter table person add constraint person_pid_pk primary key(pid);
将person的主键约束删除掉该怎么操做呢?
alter table person drop constraint person_pid_pk;
1.三、rownum
rownum:表示行号,实际上这是一个列的列名,可是这个列咱们称为伪列,此列尅在每张表中出现。
例如,在咱们查询雇员表的时候,加上rownum这个列名称
select rownum,empno,ename,job,sal,hiredate from emp;
从执行的效果来看,rownum自己采用自动编号的形式出现。
咱们扩展下rownum的应用,如今咱们只想显示前5条雇员信息,该如何实现呢?
select rownum,empno,ename,job,sal,hiredate from emp where rownum<=5;
既然能够查询前5条数据,那么,咱们如今要求提升了,查询中间的5条数据
select rownum,empno,ename,job,sal,hiredate from emp where rownum between 5 and 10;
看似没有问题的语句却查不出数据来,到底哪里出错了呢?
若是如今要想进行中间的截取操做,则只能采用子查询,例如如今假设每页显示5条,第二页应该显示6~10条,那么对于数据库操做来说,它在查询的时候应该首先查询出1~10条,以后再在查询的结果中截取出后5条。
select * from (select rownum m,empno,ename,job,sal,hiredate from emp where rownum<=10) temp where temp.m>5;
若是如今要求输出最后的4条呢?
select * from (select rownum m,empno,ename,job,sal,hiredate from emp where rownum<=15) temp where temp.m>10;
1.四、集合操做
在Oracle中提供了三种类型集合的操做,并(union)、交(intersect)、差(minus)
|-union:将多个查询的结果组合到一个查询结果中,没有重复的内容
|-union all:将多个查询结果组合到一个查询之中,可是包含了重复值
|-intersect:返回多个查询结果中相同的部分
|-minus:返回两个查询结果的差集
为了更好的观察查询结果,咱们将复制emp表,将20部门的雇员信息取出来
create table emp20 as select * from emp where deptno=20;
1) 验证union
返回两个集合的全部内容,不包含重负的内容
select * from emp
union
select * from emp20;
2) 验证union all
返回两个集合的全部内容,包含重复内容
select * from emp
union all
select * from emp20;
3) 验证intersect
返回多个查询结果中相同的部分
select * from emp
intersect
select * from emp20;
由于两张表中只有20部门的雇员信息是重复的,全部实际上返回的相同内容就是表emp20的内容
4) 验证minus
返回两个查询结果的差集
select * from emp
minus
select * from emp20;
1.五、交表、约束、查询综合练习
题目背景:
有某个学生运动会比赛信息的数据库,保存了以下的表:
|-运动员sporter(运动员编号sporterid,运动员姓名name,运动员性别sex,所属系号department)
|-项目item(项目编号itemid,项目名称itemname,项目比赛地点location)
|-成绩grade(运动员编号sporterid,项目编号itemid,积分mark)
功能要求
1) 建表
--定义各个表的主码外码约束
--运动员的姓名和所属系别不能为空值
--积分要么为空值,要么为六、四、二、0,分别表明第1、第2、第三和其余名次的积分
create table sporter(
sporterid number(4) primary key not null,
name varchar2(50) not null,
sex varchar2(3) not null,
department varchar2(30) not null,
constraint sporter_sex_ck check(sex in('男','女'))
);
create table item(
itemid varchar2(4) primary key not null,
itemname varchar2(50) not null,
location varchar2(50) not null
);
create table grade(
sporterid number(4),
itemid varchar2(4),
mark number(2),
constraint sporter_grade_sporterid_fk foreign key(sporterid) references sporter(sporterid) on delete cascade,
constraint sporter_item_itemid_fk foreign key(itemid) references item(itemid) on delete cascade,
constraint grade_mark_ck check(mark in(6,4,2,0))
);
2) 数据
运动员sporter
insert into sporter(sporterid,name,sex,department) values(1001,'李明','男','计算机系');
insert into sporter(sporterid,name,sex,department) values(1002,'张三','男','数学系');
insert into sporter(sporterid,name,sex,department) values(1003,'李四','男','计算机系');
insert into sporter(sporterid,name,sex,department) values(1004,'王二','男','物理系');
insert into sporter(sporterid,name,sex,department) values(1005,'李娜','女','心理系');
insert into sporter(sporterid,name,sex,department) values(1006,'孙俪','女','数学系');
项目item
insert into item(itemid,itemname,location) values('x001','男子五公里','一操场');
insert into item(itemid,itemname,location) values('x002','男子标枪','一操场');
insert into item(itemid,itemname,location) values('x003','男子跳远','二操场');
insert into item(itemid,itemname,location) values('x004','女子跳高','二操场');
insert into item(itemid,itemname,location) values('x005','女子三公里','三操场');
积分grade
insert into grade(sporterid,itemid,mark) values(1001,'x001',6);
insert into grade(sporterid,itemid,mark) values(1002,'x001',4);
insert into grade(sporterid,itemid,mark) values(1003,'x001',2);
insert into grade(sporterid,itemid,mark) values(1004,'x001',0);
insert into grade(sporterid,itemid,mark) values(1001,'x003',4);
insert into grade(sporterid,itemid,mark) values(1002,'x003',6);
insert into grade(sporterid,itemid,mark) values(1004,'x003',2);
insert into grade(sporterid,itemid,mark) values(1005,'x004',6);
insert into grade(sporterid,itemid,mark) values(1006,'x004',4);
3) 要求
求出目前总积分最高的系名,及其积分
--全部的系名都在sporter表中,而积分在grade表中,因此sporter和grade进行关联查询
select s.department,sum(g.mark) sum
from sporter s,grade g
where s.sporterid=g.sporterid
group by s.department
order by sum desc;
--使用rownum最方便
select * from(
select s.department,sum(g.mark) sum
from sporter s,grade g
where s.sporterid=g.sporterid
group by s.department
order by sum desc)
where rownum=1;
第五次
一、Oracle数据库
1.一、视图
视图的功能:一个视图实际上就是封装了一条复杂的查询语句
建立视图的语法以下:
create view 视图名称 as 子查询
|-实际上此时的子查询就表示一条很是复杂的查询语句
创建一个视图:此视图包含了所有的20部门的雇员信息(雇员编号,姓名,工做,雇佣日期)
create view empv20 as select empno,ename,job,hiredate from emp where deptno=20;
视图建立完成以后,就能够像查找表那样直接对视图进行查询的操做了。
select * from empv20;
此时,咱们经过视图查询出20部门的雇员信息,也就是,能够使用视图包装的查询语句完成咱们的操做。可是,咱们思考下,如今这个视图中一样只包含了4个字段的信息,若是,如今但愿多包含一个字段呢?
create view empv20 as select empno,ename,job,sal,hiredate from emp where deptno=20;
此时,系统会报错,名称已有现有对象使用。也就是说,该名称的视图已经存在了,因此,在建立视图的时候是不容许重名的,那么,咱们只能先删除掉这个视图而后进行新视图的建立。该如何删除视图呢?
drop view 视图名称;
因此,相似于删除表的操做,咱们将上面建立的视图empv20删除
drop view empv20;
删除成功后,从新执行建立视图的语句
create view empv20 as select empno,ename,job,sal,hiredate from emp where deptno=20;
可是,咱们应该发现,若是全部的代码都这样去写确定很麻烦,由于若是要想对视图进行修改操做,则确定先要删除掉视图,再进行新视图的建立才能达到目的,因此在Oracle中为了方便用户修改视图,提供了一种替换的命令,此时完整的视图建立语法以下:
create or replace 视图名称 as 子查询;
按照上面的语法格式,咱们在更改视图的时候就不须要先执行删除操做了,系统会为用户自动进行删除及重建的功能。
create or replace view empv20 as select empno,ename,job,sal,hiredate from emp where deptno=20;
此时,系统不会提示任何错误,表示该视图删除及建立成功。
咱们说视图其实是封装了一个很是复杂的查询语句。下面咱们使用视图来封装一个很是复杂的查询。此查询返回部门名称、部门人数、平均工资以及最低工资的雇员姓名。首先看看之前的写法
select d.dname,ed.c,ed.a,e.ename
from dept d,
(
select count(empno) c,deptno,avg(sal) a,min(sal) min from emp e
group by deptno
) ed,emp e
where d.deptno=ed.deptno and e.sal=ed.min;
若是在开发中每次都写如此之长的SQL语句,则确定很不方便,因此此时就能够经过创建师视图简化操做,方便用户作查询。
create or replace view myempv as
select d.dname,ed.c,ed.a,e.ename
from dept d,
(
select count(empno) c,deptno,avg(sal) a,min(sal) min from emp e
group by deptno
) ed,emp e
where d.deptno=ed.deptno and e.sal=ed.min;
在之后的操做中只须要查询该视图就能够获得结果,而不须要再次执行那么长的SQL语句。
建立一个只包含20部门的雇员视图
create or replace view mepv20
as
select * from emp where deptno=20;
视图建立成功。下面进行视图的更新操做,咱们应该记住,在视图中是不该该包含真实数据的,并且在此程序中,建立的视图其实是存在建立条件的,此条件是deptno=20.若是如今将视图中的7369的部门编号修改成30呢?
update empv20 set deptno=30 where empno=7369;
更新成功,如今咱们查询该视图,
select * from mepv20;
发如今视图中已经没有7369这个雇员了。那么,在咱们的原始表emp中呢?
select * from emp;
发如今emp表中的编号为7369的雇员的部门编号已经修改成30,咱们思考下,这样的更新操做合适吗?很明显,是不合适的,咱们在建立视图的时候是有条件的,一旦修改以后,该条件被破坏。因此在建立视图的时候SQL中提供了两个很重要的参数:
|-with check option:不能更新视图的建立条件
下面咱们在视图建立中使用此参数
create or replace view empv20
as
select * from emp where deptno=20
with check option;
咱们再对建立的视图进行更新操做
update mepv20 set deptno=30 where empno=7566;
此时,系统报错,提示:视图 with check option where 子句违规
很明显,建立条件不能更新,那么其余字段呢,例如:如今将7566的雇员姓名修改成“约翰”
update empv20 set ename='约翰' where empno=7566;
更新成功,也就是说在使用了上述的with约束后,在更新视图时,除了建立条件不能更新其余字段都可以更新。
可是,咱们说视图自己的做用仍是用来查询的,因此不该该容许修改,因此此时能够使用第二个参数:
|-with read only:建立的视图只读,即只能读取操做
建立只读视图
create or replace view empv20
as
select * from emp where deptno=20
with read only;
再次执行更新操做,更新雇员的姓名
update empv20 set ename='约翰' where empno=7566;
提示错误:没法对只读视图进行DML操做。
1.二、序列
在不少数据库系统中都存在一个自动增加的列,若是如今要想在Oracle中完成自动增加的功能,则只能依靠序列完成,全部的自动增加操做,须要用户手工完成处理。
序列的建立格式:
create sequence sequence
[increment by n][start with n]
[{maxvalue n | nomaxvalue}]
[{minvalue n | nominvalue}]
[cycle | nocycle]
[{cache n | nocache}];
建立一个myseq的序列,验证自动增加的操做
create sequence myseq;
序列建立完成以后,全部的自动增加应该由用户本身处理,在序列中提供了如下两种操做:
|-nextVal:取得序列的下一个内容
|-currVal:取得序列的当前内容
如今咱们先创建一张用于验证序列的表
create table testseq(
next number,
curr number
);
下面向表中添加数据,添加数据的时候须要手工使用序列
使用序列插入数据
insert into testseq(next,curr) values(myseq.nextval,myseq.currval);
将以上的插入语句执行5次
咱们查询下testseq表,看看序列的变化
select * from testseq;
从查询结果中咱们发现,nextval的内容始终在进行自动增加的操做,而curr使用取出当前操做的序列结果,也就是说,如今的这种序列,每次增加的幅度是1,那么也能够修改序列的增加幅度。
能够使用如下的一个参数:
|-每次增加长度:increment by 长度
从新创建序列
drop sequence myseq;
create sequence myseq increment by 2;
此时,序列已经正常的建立,建立以后来测试下,序列的操做,从新建立testseq表
drop table testseq;
create table testseq(
next number,
curr number
);
从新进行数据的插入操做,插入5次
insert into testseq(next,curr) values(myseq.nextval,myseq.currval);
再次查询testseq表,观察序列的变化
select * from testseq;
从序列的结果来看,每次取得都是奇数。
默认状况下,序列从1开始的,那么能够使用start with来指定其开始的位置
drop sequence myseq;
create sequence myseq increment by 2 start with 10;
这里指定序列开始点为10,之后直接从10开始进行序列的计算。
下面咱们从新建立下该序列,让其取值固定在一、三、五、七、9,并循环序列
drop sequence myseq;
create sequence myseq
maxvalue 10
increment by 2 start with 1
cache 2 cycle;
从新创建testseq表,插入数据,测试最终的结果,能够发现序列的内容是循环出现的,可是咱们说在实践中,序列使用最多的语法是:create sequence 序列名称。其余选项使用默认值。
1.三、同义词
在前面咱们使用过这样的查询语句:
select sysdate from dual;
咱们知道dual是一张虚拟表,那么虽然是虚拟表,但是此表究竟是在哪里定义的呢?
经过测试,咱们发如今sys帐户下存在dual表。如今问题出现了,既然dual表是sys帐户下的,那么根据咱们前面的知识,若是想要在scott用户中使用dual表时,正确的作法是:
select sysdate from sys.dual;
可是咱们在scott帐户下是这样写的
select sysdate from dual;
这是为何呢?此时,实际上就是同义词的做用。什么是同义词?同义词可让其余用户经过一个名称方便的访问”用户名.表名称“。
建立同义词的语法:
create synonym 同义词名称 for 用户名.表名称;
下面咱们将scott表的emp定义emp的同义词:
create sysnonym emp for scott.emp;
若是要删除一个同义词,能够使用以下的语法格式:
drop sysnonym 同义词名称;
因此,删除上面建立的同义词:
drop sysnonym emp;
可是,此种特性只适用于Oracle数据库。
1.四、用户管理
在Oracle中能够对用户进行创建和受权的操做。
建立用户的语法是:
create user 用户名 identified by 密码;
假设如今要建立一个test用户,密码为123
create user test identified by 123;
建立用户成功事后,是否能够登陆呢?显然是不行的,在登陆请安必须为新建立的用户授予相关的权限才能执行相应的操做。
为用户受权的格式以下:
grant 权限1,权限2,...... to 用户名;
因此,为了新建立的用户test可以链接数据库,咱们须要为它受权
grant create session to test;
以后咱们就能使用test正常登录了。
那么,咱们开始常见一张表吧。
但是,咱们发现,系统又提示权限不足。很明显的知道,当前用户test没有建立表的权限,既然如此,咱们就为它授予建立表的权限。在此以前,咱们给出一个这样的结论:对于一个新建立的用户,全部的权限均要分别赋予,该用户才能进行相应的操做。若是如今假设要想把多个权限一次性赋予一个用户,则能够讲这些权限先定义成一组角色的集合。
在Oracle中提供了两个主要角色:connect、resource,能够直接把这啷个角色赋予test用户。
grant connect,resource to test;
忽然,test用户密码忘记了,那么如何修改一个用户的密码呢?固然该操做只有超级管理员才有权限
alter user 用户名 identified by 密码;
将test的用户密码修改成hello
alter user test identified by hello;
在通常的系统中存在这样的状况,在用户第一次登录的时候能够修改密码,因此要想完成此功能,能够手工让一个密码失效,格式以下:
alter user 用户名 password expire;
如今咱们能够设置test的当前密码失效
alter user test password expire;
若是系统中某个用户须要被锁住,该如何操做呢?
alter user 用户名 account lock;
如今因为某些缘由,咱们须要将test用户锁住
alter user test account lock;
那么,test用户就不能链接数据库了。
若是要解锁test呢?
alter user 用户名 account unlock;
好了,如今咱们解锁test
alter user test account unlock;
那么,test用户就能正常链接数据库了。
如今咱们须要使用test用户来访问scott用户下的emp表
select * from scott.emp;
按照前面的知识,该查询时没有问题的,可是系统提示错误说:scott.emp表不存在。怎么回事?
再想一想前面的一句话,”咱们须要为新建立的用户分别授予相应的权限来执行相应的操做“,很明显,test没有访问其余用户下表的权限,因此这么操做
grant select,delete on scott.emp to test;
咱们将查询和删除emp表的权限授予给test用户
既然能够授予权限,那么也能够回收权限,回收权限使用revoke语法。,语法格式以下:
revoke 权限名 on 用户表名称 from 用户;
若是咱们不但愿test用户查询和删除scott的emp表,
revoke select,delete on scott.emp from test;
1.五、数据库的备份和恢复
数据库在运行的期间都是须要不断的进行备份的,万一假设系统崩溃了,能够从备份中恢复数据。
Oracle在安装完成以后能够使用两个命名进行数据库的备份和恢复:
|-数据库备份:exp
|-数据库恢复:imp
1.六、嵌套表
嵌套表:在一个表中还包含另一个子表
例如:如今有一种状况,一个部门可能承接多个项目,若是此时,按照最原始的方法设计,那么定义两张表,department表,project表
create table department(
deptno number(2) primary key not null,
dname varchar2(50) not null
);
create table project(
proid number(4) primary key not null,
proname varchar2(50) not null,
deptno number(2),
constraint department_project_deptno foreign key(deptno) references department(deptno) on delete cascade
);
这是咱们最多见的思路,并且自己也属于一个正确的作法,可是在Oracle中引入了嵌套表的概念,能够直接将项目表的类型做为一个department表的字段类型,达到嵌套的目的。
可是,要想完成一个嵌套表的制做,则首先要保证一点:由于数据库在建立数据表的时候都要指定字段的类型,因此嵌套表自己也须要一样指定类型,那么这种类型就须要单独的定义:
create type project_ty as object(
proid number(4),
proname varchar2(50),
prodate date
);
/
类型建立成功以后,并不意味着此类型能够直接使用,由于此类型是一个完整的类型,因此要为此类型指定一个名称
create type project_nt as table of project_ty;
/
以上的操做表示之后直接使用project_nt表示project_ty类型,就相似于varchar2表示字符串是同样的,此时能够使用此类型建立department表
create table department(
deptno number(2) primary key not null,
dname varchar2(50) not null,
projects project_nt
)nested table projects store as project_nt_tab_temp;
对于插入语句来说,须要指定每一个project_ty的类型
insert into department(deptno,dname,projects)
values(
1,'技术部',
project_nt(
project_ty(1001,'ERP',sysdate),
project_ty(1002,'CRM',sysdate),
project_ty(1003,'OA',sysdate)
)
);
此时,查询嵌套表,能够返回多个项目
select * from department;
若是这个时候,咱们须要查看一个部门的所有项目的话,则须要查询嵌套表
select * from table
(select projects from department where deptno=1);
若是如今咱们须要更新项目编号为1001的项目名称,将此项目名称更新为“测试项目”
update table (select projects from department where deptno=1) pro
set value(pro)=project_ty(1001,'测试项目',to_date('1998-09-21','yyyy-mm-dd')) where pro.proid=1001;
1.七、可变数组
可变数组属于嵌套表的升级版,在可变数组中,实际上就是将内部的嵌套表的内容的长度进行了限制。
例如,一个部门有多个工人,若是按照可变数组的作法,确定首先要作出一个工人的类型。
create type worker_info as object(
id number(4),
name varchar2(50),
sex varchar2(6)
);
/
下面再定义数组类型
create type worker_info_list as varray(10) of worker_info;
/
定义部门表,一个部门中可能存在多个工人
drop table department;
create table department(
deptno number(2) primary key not null,
dname varchar2(50) not null,
workers worker_info_list
);
插入测试数据
insert into department(deptno,dname,workers)
values(20,'后勤部',
worker_info_list(
worker_info(1,'张三','男'),
worker_info(2,'李四','男'),
worker_info(3,'王五','男')
)
);
查询所有
select * from department;
除了以上的全部内容以外,对于数据库的开发中,像过程之类的基本不用了,由于如今的不少地方都使用程序完成功能。
并且,对于高级开发部分:游标、触发器、包、函数。基本上不多去直接调用。
1.八、数据库设计范式
数据库设计范式实际上很是的重要,可是从实际的开发来看,若是真的所有按照范式去作,则这个程序无法写,包括查询语句也会变得复杂。
在Oracle中的scott用户的所有表,实际上就已经很好的体现了一张设计思路,雇员-部门的关系。
1) 第一范式
例如,如今假设有以下的数据库建立脚本
create table person(
pid number(4) primary key not null,
name varchar2(50),
info varchar(200)
);
插入如下测试数据
insert into person(pid,name,info) values(1111,'张三','1983年11月23日出生,如今的住址是:北京市西城区。。。。。');
实际上对于人员来看,由如下几部分组成:
|-生日:1983年1月23日
|-省市:北京
|-地区:西城区
|-详细的信息:。。。。。
每一个字段不可再分,因此,以上的数据库建立脚本修改以下:
create table person(
pid number(4) primary key not null,
name varchar2(50),
birthday date,
area varchar2(200),
subarea varchar2(200),
address varchar2(200)
);
这种设计看上去每一个字段是不可再分的,可是咱们应该会注意到,在一些网站的注册中,会要求用户分别输入“姓”和“名”,因此,可将上面的设计修改以下:
create table person(
pid number(4) primary key not null,
姓 varchar2(50),
名 varchar2(50),
birthday date,
area varchar2(200),
subarea varchar2(200),
address varchar2(200)
);
因此,在设计表字段的时候,最好保证每一个字段均不能再分。
2) 第二范式
第一范式的要求很是简单,保证每一个字段有意义。可是若是全部的操做都使用第一范式,那么会存在问题:
如今创建一张学生选课表:学号、姓名、年龄、课程名称、成绩、学分
create table selectcourse(
stuno varchar2(50),
stuname varchar2(50),
stuage number,
cname varchar2(50),
grade number,
credit number
);
以上的脚本符合第一范式的要求,可是若是按照第一范式设计的话,会存在问题:
insert into selectcourse values('s001','张三',21,'JAVA',89,0.3);
insert into selectcourse values('s001','李四',20,'JAVA',78,0.3);
insert into selectcourse values('s001','王五',23,'JAVA',80,0.3);
insert into selectcourse values('s001',赵六',22,'JAVA',90,0.3);
从以上的数据库脚本上能够发现,全部的课程信息冗余了,并且还存在如下问题:
|-若是一门课程没有一个学生选择,则此而成就从学校完全消失了
|-课程中自己也应该包含一个课程的编号,可是若是按照以上的设计,则课程编号确定重复
|-若是要更改课程信息,则要更改许多条记录
咱们使用第二范式修改数据库脚本:
|-学生是一个实体--学生表
create table student(
stuno varchar2(50) primary key not null,
stuname varchar2(50),
stuage number
);
|-课程也应该是一个实体--课程表
create table course(
cid number(5) primary key not null,
cname varchar2(50),
credit number
);
|-学生选课信息也是一个实体--学生选课表
create table selectcourse(
stuno varchar2(50),
cid number(5),
grade number,
加入外键关联,由于学生没了,成绩就没了,由于课程没了,成绩就没了
);
以上设计解决了如下问题:
|-学生不选课的时候,课程信息不会消失
|-更新课程的时候直接更新课程表便可
|-全部的关联关系在关系表中体现。
3) 第三范式
在实际开发中,第三范式的使用是最多的。
例如,如今要求设计一张学生表,包含学号、姓名、年龄、所在院校、学院地址、学院电话,此时确定不能使用第一范式,可是如今若是使用的是第二范式呢?
create table student(
stuno varchar2(50) primary key not null,
stuname varchar2(50),
stuage number
);
create table collage(
cid number(4) primary key not null,
cname varchar2(50) not not null,
caddress varchar2(200) not nul,
ctel varchar2(200) not null
);
create table studentcollage(
stuno varchar2(50),
cid number(4),
设置主-外键关系
);
按照上面的设计,一个学生能够同时在多个学院同时上课,多个学院会同时有同一个学生,此时,最好的作法是:一个学院包含多个学生,一个学生属于一个学院,实际上,此设计就彻底相似于部门和雇员表的设计结构。
create table collage(
cid number(4) primary key not null,
cname varchar2(50) not not null,
caddress varchar2(200) not nul,
ctel varchar2(200) not null
);
create table student(
stuno varchar2(50) primary key not null,
stuname varchar2(50),
stuage number,
cid number(4),
创建主-外键关系
);
该设计是一个很明确的一对多的关系设计。
数据库的惟一原则:
|-数据库表的关联查询越少越好,SQL语句的复杂度越低越好。
1.九、数据库设计工具
在实际中数据库也有本身的设计工具,比较经常使用的就是Sybase的PowerDesigner开发工具,此工具能够方便的作各类设计,启动以后,能够使用此工具,进行数据库的建模设计。
启动PowerDesigner后,选择新建,Physical Data Model,选择Oracle数据库
下面使用PowerDesigner工具将Oracle中的dept和emp表进行还原
建立表--在工具中进行主-外键的操做--获得关系以后,就能够经过Powerdesigner工具进行数据库脚本的建立了。
1.十、数据库设计分析
1) 要求
设计要求,要求设计一个网上购物程序(使用Powerdesigner创建模型并编写测试数据),有如下的需求
|-管理员能够再后台添加商品,每一个商品属于一个商品组
|-能够对管理员进行分组,对每一组进行分别受权,即一个管理员组能够有多个管理员,一个管理员组有多个权限,一个管理员能够再多个组
|-用户能够本身购买商品,购买商品时要在订单表中添加信息,一个用户能够同时购买多个商品,用户能够选择本身所在的地区进行商品的派送
|-用户能够根据本身的购买积分,对商品进行折扣
2) 实现
根据第一个要求,一个商品属于一个商品组,则此时应该创建一个“一对多”的关系
根据第二个要求,能够对管理员进行分组,须要管理员表、管理员组表、权限表、管理员-管理员组表、管理员组-权限表
管理员和商品表也要存在关系
须要一个用户表,与其产生关系的有地区表、子地区表、订单表、订单详情表、积分表
正常状况下,一份订单确定会按照以上的格式显示,那么请问,这样一来要查询多少张表?
|-用户表(用户姓名、用户电话、用户地址)
|-地区表-子地区表(用户地区)
|-订单表、订单详情表(商品总价、订单日期、邮政编码)
本查询须要同时查询6张表。本程序中的全部代码都是按照标准范式完成的,因此此时出现了以上的问题。
在开发中减小多表查询的方法能够经过冗余数据完成。</pre>
<p> </p>
<pre name="code" >Oracle 笔记
1
韩顺平老师 oracle教程笔记
1.Oracle认证,与其它数据库比较,安装 Oracle安装会自动的生成sys用户和system用户: (1)sys用户是超级用户,具备最高权限,具备sysdba角色,有create database的权限,该用户默认的密码是change_on_install (2)system用户是管理操做员,权限也很大。具备sysoper角色,没有create database的权限,默认的密码是manager (3)通常讲,对数据库维护,使用system用户登陆就能够拉 也就是说sys和system这两个用户最大的区别是在于有没有create database的权限。
2.Oracle的基本使用--基本命令
sql*plus的经常使用命令
链接命令 1.conn[ect] 用法:conn 用户名/密码@网络服务名[as sysdba/sysoper]当用特权用户身份链接时,必须带上as sysdba或是as sysoper 2.disc[onnect] 说明: 该命令用来断开与当前数据库的链接 3.psssw[ord] 说明: 该命令用于修改用户的密码,若是要想修改其它用户的密码,须要用sys/system登陆。 4.show user 说明: 显示当前用户名 5.exit 说明: 该命令会断开与数据库的链接,同时会退出sql*plus 文件操做命令 1.start和@ 说明: 运行sql脚本 案例: sql>@ d:\a.sql或是sql>start d:\a.sql 2.edit 说明: 该命令能够编辑指定的sql脚本 案例: sql>edit d:\a.sql,这样会把d:\a.sql这个文件打开 3.spool 说明: 该命令能够将sql*plus屏幕上的内容输出到指定文件中去。 案例: sql>spool d:\b.sql 并输入 sql>spool off 交互式命令 1.& 说明:能够替代变量,而该变量在执行时,须要用户输入。 select * from emp where job='&job'; 2.edit 说明:该命令能够编辑指定的sql脚本 案例:SQL>edit d:\a.sql 3.spool 说明:该命令能够将sql*plus屏幕上的内容输出到指定文件中去。 spool d:\b.sql 并输入 spool off 显示和设置环境变量 概述:能够用来控制输出的各类格式,set show若是但愿永久的保存相关的设置,能够去修改glogin.sql脚本
Oracle 笔记
2
1.linesize 说明:设置显示行的宽度,默认是80个字符 show linesize set linesize 90 2.pagesize说明:设置每页显示的行数目,默认是14 用法和linesize同样 至于其它环境参数的使用也是大同小异
3.oracle用户管理
oracle用户的管理 建立用户 概述:在oracle中要建立一个新的用户使用create user语句,通常是具备dba(数据库管理员)的权限才能使用。 create user 用户名 identified by 密码; (oracle有个毛病,密码必须以字母开头,若是以字母开头,它不会建立用户) 给用户修改密码 概述:若是给本身修改密码能够直接使用 password 用户名 若是给别人修改密码则须要具备dba的权限,或是拥有alter user的系统权限 SQL> alter user 用户名 identified by 新密码 删除用户 概述:通常以dba的身份去删除某个用户,若是用其它用户去删除用户则须要具备drop user的权限。 好比 drop user 用户名 【cascade】 在删除用户时,注意: 若是要删除的用户,已经建立了表,那么就须要在删除的时候带一个参数cascade; 用户管理综合案例 概述:建立的新用户是没有任何权限的,甚至连登录的数据库的权限都没有,须要为其指定相应的权限。给一个用户赋权限使用命令grant,回收权限使用命令revoke。 为了给讲清楚用户的管理,这里我给你们举一个案例。 SQL> conn xiaoming/m12; ERROR: ORA-01045: user XIAOMING lacks CREATE SESSION privilege; logon denied 警告: 您再也不链接到 ORACLE。 SQL> show user; USER 为 "" SQL> conn system/p; 已链接。 SQL> grant connect to xiaoming; 受权成功。 SQL> conn xiaoming/m12; 已链接。 SQL> 注意:grant connect to xiaoming;在这里,准确的讲,connect不是权限,而是角色。
如今说下对象权限,如今要作这么件事情: * 但愿xiaoming用户能够去查询emp表 * 但愿xiaoming用户能够去查询scott的emp表
Oracle 笔记
3
grant select on emp to xiaoming * 但愿xiaoming用户能够去修改scott的emp表 grant update on emp to xiaoming * 但愿xiaoming用户能够去修改/删除,查询,添加scott的emp表 grant all on emp to xiaoming * scott但愿收回xiaoming对emp表的查询权限 revoke select on emp from xiaoming //对权限的维护。 * 但愿xiaoming用户能够去查询scott的emp表/还但愿xiaoming能够把这个权限继续给别人。 --若是是对象权限,就加入 with grant option grant select on emp to xiaoming with grant option 个人操做过程: SQL> conn scott/tiger; 已链接。 SQL> grant select on scott.emp to xiaoming with grant option; 受权成功。 SQL> conn system/p; 已链接。 SQL> create user xiaohong identified by m123; 用户已建立。 SQL> grant connect to xiaohong; 受权成功。 SQL> conn xiaoming/m12; 已链接。 SQL> grant select on scott.emp to xiaohong; 受权成功。 --若是是系统权限。 system给xiaoming权限时: grant connect to xiaoming with admin option 问题:若是scott把xiaoming对emp表的查询权限回收,那么xiaohong会怎样? 答案:被回收。 下面是个人操做过程: SQL> conn scott/tiger; 已链接。 SQL> revoke select on emp from xiaoming; 撤销成功。 SQL> conn xiaohong/m123; 已链接。 SQL> select * from scott.emp; select * from scott.emp 第 1 行出现错误: ORA-00942: 表或视图不存在 结果显示:小红受到诛连了。。 使用profile管理用户口令 概述:profile是口令限制,资源限制的命令集合,当创建数据库的,oracle会自动创建名称为default的profile。当创建用户没
Oracle 笔记
4
有指定profile选项,那么oracle就会将default分配给用户。 1.帐户锁定 概述:指定该帐户(用户)登录时最多能够输入密码的次数,也能够指定用户锁定的时间(天)通常用dba的身份去执行该命令。 例子:指定scott这个用户最多只能尝试3次登录,锁定时间为2天,让咱们看看怎么实现。 建立profile文件 SQL> create profile lock_account limit failed_login_attempts 3 password_lock_time 2; SQL> alter user scott profile lock_account; 2.给帐户(用户)解锁 SQL> alter user tea account unlock; 3.终止口令 为了让用户按期修改密码能够使用终止口令的指令来完成,一样这个命令也须要dba的身份来操做。 例子:给前面建立的用户tea建立一个profile文件,要求该用户每隔10天要修改本身的登录密码,宽限期为2天。看看怎么作。 SQL> create profile myprofile limit password_life_time 10 password_grace_time 2; SQL> alter user tea profile myprofile; 口令历史 概述:若是但愿用户在修改密码时,不能使用之前使用过的密码,可以使用口令历史,这样oracle就会将口令修改的信息存放到数据字典中,这样当用户修改密码时,oracle就会对新旧密码进行比较,当发现新旧密码同样时,就提示用户从新输入密码。 例子: 1)创建profile SQL>create profile password_history limit password_life_time 10 password_grace_time 2 password_reuse_time 10 password_reuse_time //指定口令可重用时间即10天后就能够重用 2)分配给某个用户
删除profile 概述:当不须要某个profile文件时,能够删除该文件。 SQL> drop profile password_history 【casade】 注意:文件删除后,用这个文件去约束的那些用户统统也都被释放了。。 加了casade,就会把级联的相关东西也给删除掉
4.oracle表的管理(数据类型,表建立删除,数据CRUD操做)
指望目标
? 1.掌握oracle表的管理(建立/维护)
? 2.掌握对oracle表的各类查询技巧
? 3.学会建立新的oracle数据库 oracle的表的管理 表名和列的命名规则
? 必须以字母开头
? 长度不能超过30个字符
? 不能使用oracle的保留字
? 只能使用以下字符 A-Z,a-z,0-9,$,#等
oracle支持的数据类型? 字符类 char 定长 最大2000个字符。
Oracle 笔记
5
例子:char(10) ‘小韩’前四个字符放‘小韩’,后添6个空格补全 如‘小韩 ’ varchar2(20) 变长 最大4000个字符。 例子:varchar2(10) ‘小韩’ oracle分配四个字符。这样能够节省空间。 clob(character large object) 字符型大对象 最大4G char 查询的速度极快浪费空间,查询比较多的数据用。 varchar 节省空间 数字型 number范围 -10的38次方 到 10的38次方 能够表示整数,也能够表示小数 number(5,2) 表示一位小数有5位有效数,2位小数 范围:-999.99到999.99 number(5) 表示一个5位整数 范围99999到-99999 日期类型 date 包含年月日和时分秒 oracle默认格式 1-1月-1999 timestamp 这是oracle9i对date数据类型的扩展。能够精确到毫秒。 ? 图片 blob 二进制数据 能够存放图片/声音 4G 通常来说,在真实项目中是不会把图片和声音真的往数据库里存放,通常存放图片、视频的路径,若是安全须要比较高的话,则放入数据库。 怎样建立表 建表 --学生表 create table student ( ---表名 xh number(4), --学号 xm varchar2(20), --姓名 sex char(2), --性别 birthday date, --出生日期 sal number(7,2) --奖学金 ); --班级表 CREATE TABLE class( classId NUMBER(2), cName VARCHAR2(40) ); 修改表 ? 添加一个字段 SQL>ALTER TABLE student add (classId NUMBER(2)); ? 修改一个字段的长度 SQL>ALTER TABLE student MODIFY (xm VARCHAR2(30)); ? 修改字段的类型/或是名字(不能有数据) 不建议作 SQL>ALTER TABLE student modify (xm CHAR(30)); ? 删除一个字段 不建议作(删了以后,顺序就变了。加就没问题,应为是加在后面) SQL>ALTER TABLE student DROP COLUMN sal;
Oracle 笔记
6
? 修改表的名字 不多有这种需求 SQL>RENAME student TO stu; ? 删除表 SQL>DROP TABLE student; 添加数据 全部字段都插入数据 INSERT INTO student VALUES ('A001', '张三', '男', '01-5月-05', 10); oracle中默认的日期格式‘dd-mon-yy’ dd日子(天) mon 月份 yy 2位的年 ‘09-6月-99’ 1999年6月9日 修改日期的默认格式(临时修改,数据库重启后仍为默认;如要修改须要修改注册表) ALTER SESSION SET NLS_DATE_FORMAT ='yyyy-mm-dd'; 修改后,能够用咱们熟悉的格式添加日期类型: INSERT INTO student VALUES ('A002', 'MIKE', '男', '1905-05-06', 10); 插入部分字段 INSERT INTO student(xh, xm, sex) VALUES ('A003', 'JOHN', '女'); 插入空值 INSERT INTO student(xh, xm, sex, birthday) VALUES ('A004', 'MARTIN', '男', null); 问题来了,若是你要查询student表里birthday为null的记录,怎么写sql呢? 错误写法:select * from student where birthday = null; 正确写法:select * from student where birthday is null; 若是要查询birthday不为null,则应该这样写: select * from student where birthday is not null; 修改数据 ? 修改一个字段 UPDATE student SET sex = '女' WHERE xh = 'A001'; ? 修改多个字段 UPDATE student SET sex = '男', birthday = '1984-04-01' WHERE xh = 'A001'; 修改含有null值的数据 不要用 = null 而是用 is null; SELECT * FROM student WHERE birthday IS null; ? 删除数据 DELETE FROM student; 删除全部记录,表结构还在,写日志,能够恢复的,速度慢。 Delete 的数据能够恢复。 savepoint a; --建立保存点 DELETE FROM student; rollback to a; --恢复到保存点 一个有经验的DBA,在确保完成无误的状况下要按期建立还原点。 DROP TABLE student; --删除表的结构和数据; delete from student WHERE xh = 'A001'; --删除一条记录; truncate TABLE student; --删除表中的全部记录,表结构还在,不写日志,没法找回删除的记录,速度快。
5.oracle表查询(1)
在咱们讲解的过程当中咱们利用scott用户存在的几张表(emp,dept)为你们演示如何使用select语句,select语句在软件编程中很是有用,但愿你们好好的掌握。
Oracle 笔记
7
emp 雇员表 clerk 普员工 salesman 销售 manager 经理 analyst 分析师 president 总裁 mgr 上级的编号 hiredate 入职时间 sal 月工资 comm 奖金 deptno 部门 dept部门表 deptno 部门编号 accounting 财务部 research 研发部 operations 业务部 loc 部门所在地点 salgrade 工资级别 grade 级别 losal 最低工资 hisal 最高工资 简单的查询语句 ? 查看表结构 DESC emp; ? 查询全部列 SELECT * FROM dept; 切忌动不动就用select * SET TIMING ON; 打开显示操做时间的开关,在下面显示查询时间。 CREATE TABLE users(userId VARCHAR2(10), uName VARCHAR2 (20), uPassw VARCHAR2(30)); INSERT INTO users VALUES('a0001', '啊啊啊啊', 'aaaaaaaaaaaaaaaaaaaaaaa'); --从本身复制,加大数据量 大概几万行就能够了 能够用来测试sql语句执行效率 INSERT INTO users (userId,UNAME,UPASSW) SELECT * FROM users; SELECT COUNT (*) FROM users;统计行数 ? 查询指定列 SELECT ename, sal, job, deptno FROM emp; ? 如何取消重复行DISTINCT SELECT DISTINCT deptno, job FROM emp; ?查询SMITH所在部门,工做,薪水 SELECT deptno,job,sal FROM emp WHERE ename = 'SMITH'; 注意:oracle对内容的大小写是区分的,因此ename='SMITH'和ename='smith'是不一样的
Oracle 笔记
8
? 使用算术表达式 nvl null 问题:如何显示每一个雇员的年工资? SELECT sal*13+nvl(comm, 0)*13 "年薪" , ename, comm FROM emp; ? 使用列的别名 SELECT ename "姓名", sal*12 AS "年收入" FROM emp; ? 如何处理null值 使用nvl函数来处理 ? 如何链接字符串(||) SELECT ename || ' is a ' || job FROM emp; ? 使用where子句 问题:如何显示工资高于3000的 员工? SELECT * FROM emp WHERE sal > 3000; 问题:如何查找1982.1.1后入职的员工? SELECT ename,hiredate FROM emp WHERE hiredate >'1-1月-1982'; 问题:如何显示工资在2000到3000的员工? SELECT ename,sal FROM emp WHERE sal >=2000 AND sal <= 3000; ? 如何使用like操做符 %:表示0到多个字符 _:表示任意单个字符 问题:如何显示首字符为S的员工姓名和工资? SELECT ename,sal FROM emp WHERE ename like 'S%'; 如何显示第三个字符为大写O的全部员工的姓名和工资? SELECT ename,sal FROM emp WHERE ename like '__O%'; ? 在where条件中使用in 问题:如何显示empno为7844, 7839,123,456 的雇员状况? SELECT * FROM emp WHERE empno in (7844, 7839,123,456); ? 使用is null的操做符 问题:如何显示没有上级的雇员的状况? 错误写法:select * from emp where mgr = ''; 正确写法:SELECT * FROM emp WHERE mgr is null;
6.oracle表查询(2)
? 使用逻辑操做符号 问题:查询工资高于500或者是岗位为MANAGER的雇员,同时还要知足他们的姓名首字母为大写的J? SELECT * FROM emp WHERE (sal >500 or job = 'MANAGER') and ename LIKE 'J%'; ? 使用order by 字句 默认asc 问题:如何按照工资的从低到高的顺序显示雇员的信息? SELECT * FROM emp ORDER by sal; 问题:按照部门号升序而雇员的工资降序排列 SELECT * FROM emp ORDER by deptno, sal DESC; ? 使用列的别名排序 问题:按年薪排序 select ename, (sal+nvl(comm,0))*12 "年薪" from emp order by "年薪" asc; 别名须要使用“”号圈中,英文不须要“”号
Oracle 笔记
9
? 分页查询 等学了子查询再说吧。。。。。。。。 Clear 清屏命令 oracle表复杂查询 ? 说明 在实际应用中常常须要执行复杂的数据统计,常常须要显示多张表的数据,如今咱们给你们介绍较为复杂的select语句 数据分组 ——max,min, avg, sum, count 问题:如何显示全部员工中最高工资和最低工资? SELECT MAX(sal),min(sal) FROM emp e; 最高工资那我的是谁? 错误写法:select ename, sal from emp where sal=max(sal); 正确写法:select ename, sal from emp where sal=(select max(sal) from emp); 注意:select ename, max(sal) from emp;这语句执行的时候会报错,说ORA-00937:非单组分组函数。由于max是分组函数,而ename不是分组函数....... 可是select min(sal), max(sal) from emp;这句是能够执行的。由于min和max都是分组函数,就是说:若是列里面有一个分组函数,其它的都必须是分组函数,不然就出错。这是语法规定的 问题:如何显示全部员工的平均工资和工资总和? 问题:如何计算总共有多少员工问题:如何 扩展要求: 查询最高工资员工的名字,工做岗位 SELECT ename, job, sal FROM emp e where sal = (SELECT MAX(sal) FROM emp); 显示工资高于平均工资的员工信息 SELECT * FROM emp e where sal > (SELECT AVG(sal) FROM emp); ? group by 和 having子句 group by用于对查询的结果分组统计, having子句用于限制分组显示结果。 问题:如何显示每一个部门的平均工资和最高工资? SELECT AVG(sal), MAX(sal), deptno FROM emp GROUP by deptno; (注意:这里暗藏了一点,若是你要分组查询的话,分组的字段deptno必定要出如今查询的列表里面,不然会报错。由于分组的字段都不出现的话,就没办法分组了) 问题:显示每一个部门的每种岗位的平均工资和最低工资? SELECT min(sal), AVG(sal), deptno, job FROM emp GROUP by deptno, job; 问题:显示平均工资低于2000的部门号和它的平均工资? SELECT AVG(sal), MAX(sal), deptno FROM emp GROUP by deptno having AVG(sal) < 2000; ? 对数据分组的总结 1 分组函数只能出如今选择列表、having、order by子句中(不能出如今where中) 2 若是在select语句中同时包含有group by, having, order by 那么它们的顺序是group by, having, order by 3 在选择列中若是有列、表达式和分组函数,那么这些列和表达式必须有一个出如今group by 子句中,不然就会出错。 如SELECT deptno, AVG(sal), MAX(sal) FROM emp GROUP by deptno HAVING AVG(sal) < 2000; 这里deptno就必定要出如今group by 中 多表查询 ? 说明 多表查询是指基于两个和两个以上的表或是视图的查询。在实际应用中,查询单个表可能不能知足你的需求,(如显示sales部门位置和其员工的姓名),这种状况下须要使用到(dept表和emp表)
Oracle 笔记
10
问题:显示雇员名,雇员工资及所在部门的名字【笛卡尔集】? 规定:多表查询的条件是 至少不能少于 表的个数-1 才能排除笛卡尔集 (若是有N张表联合查询,必须得有N-1个条件,才能避免笛卡尔集合) SELECT e.ename, e.sal, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno; 问题:显示部门号为10的部门名、员工名和工资? SELECT d.dname, e.ename, e.sal FROM emp e, dept d WHERE e.deptno = d.deptno and e.deptno = 10; 问题:显示各个员工的姓名,工资及工资的级别? 先看salgrade的表结构和记录 SQL>select * from salgrade; GRADE LOSAL HISAL ------------- ------------- ------------ 1 700 1200 2 1201 1400 3 1401 2000 4 2001 3000 5 3001 9999 SELECT e.ename, e.sal, s.grade FROM emp e, salgrade s WHERE e.sal BETWEEN s.losal AND s.hisal; 扩展要求: 问题:显示雇员名,雇员工资及所在部门的名字,并按部门排序? SELECT e.ename, e.sal, d.dname FROM emp e, dept d WHERE e.deptno = d.deptno ORDER by e.deptno; (注意:若是用group by,必定要把e.deptno放到查询列里面) ? 自链接 自链接是指在同一张表的链接查询 问题:显示某个员工的上级领导的姓名? 好比显示员工‘FORD’的上级 SELECT worker.ename, boss.ename FROM emp worker,emp boss WHERE worker.mgr = boss.empno AND worker.ename = 'FORD'; 子查询 ? 什么是子查询 子查询是指嵌入在其余sql语句中的select语句,也叫嵌套查询。 ? 单行子查询 单行子查询是指只返回一行数据的子查询语句 请思考:显示与SMITH同部门的全部员工? 思路: 1 查询出SMITH的部门号 select deptno from emp WHERE ename = 'SMITH'; 2 显示 SELECT * FROM emp WHERE deptno = (select deptno from emp WHERE ename = 'SMITH'); 数据库在执行sql 是从左到右扫描的, 若是有括号的话,括号里面的先被优先执行。 ? 多行子查询 多行子查询指返回多行数据的子查询 请思考:如何查询和部门10的工做相同的雇员的名字、岗位、工资、部门号 SELECT DISTINCT job FROM emp WHERE deptno = 10; SELECT * FROM emp WHERE job IN (SELECT DISTINCT job FROM emp WHERE deptno = 10); (注意:不能用job=..,由于等号=是一对一的) ? 在多行子查询中使用all操做符
Oracle 笔记
11
问题:如何显示工资比部门30的全部员工的工资高的员工的姓名、工资和部门号? SELECT ename, sal, deptno FROM emp WHERE sal > all (SELECT sal FROM emp WHERE deptno = 30); 扩展要求: 你们想一想还有没有别的查询方法。 SELECT ename, sal, deptno FROM emp WHERE sal > (SELECT MAX(sal) FROM emp WHERE deptno = 30); 执行效率上, 函数高得多 ? 在多行子查询中使用any操做符 问题:如何显示工资比部门30的任意一个员工的工资高的员工姓名、工资和部门号? SELECT ename, sal, deptno FROM emp WHERE sal > ANY (SELECT sal FROM emp WHERE deptno = 30); 扩展要求: 你们想一想还有没有别的查询方法。 SELECT ename, sal, deptno FROM emp WHERE sal > (SELECT min(sal) FROM emp WHERE deptno = 30); ? 多列子查询 单行子查询是指子查询只返回单列、单行数据,多行子查询是指返回单列多行数据,都是针对单列而言的,而多列子查询是指查询返回多个列数据的子查询语句。 请思考如何查询与SMITH的部门和岗位彻底相同的全部雇员。 SELECT deptno, job FROM emp WHERE ename = 'SMITH'; SELECT * FROM emp WHERE (deptno, job) = (SELECT deptno, job FROM emp WHERE ename = 'SMITH'); ? 在from子句中使用子查询 请思考:如何显示高于本身部门平均工资的员工的信息 思路: 1. 查出各个部门的平均工资和部门号 SELECT deptno, AVG(sal) mysal FROM emp GROUP by deptno; 2. 把上面的查询结果看作是一张子表 SELECT e.ename, e.deptno, e.sal, ds.mysal FROM emp e, (SELECT deptno, AVG(sal) mysal FROM emp GROUP by deptno) ds WHERE e.deptno = ds.deptno AND e.sal > ds.mysal; 如何衡量一个程序员的水平? 网络处理能力, 数据库, 程序代码的优化程序的效率要很高 小总结: 在这里须要说明的当在from子句中使用子查询时,该子查询会被做为一个视图来对待,所以叫作内嵌视图,当在from子句中使用子查询时,必须给子查询指定别名。 注意:别名不能用as,如:SELECT e.ename, e.deptno, e.sal, ds.mysal FROM emp e, (SELECT deptno, AVG(sal) mysal FROM emp GROUP by deptno) as ds WHERE e.deptno = ds.deptno AND e.sal > ds.mysal; 在ds前不能加as,不然会报错 (给表取别名的时候,不能加as;可是给列取别名,是能够加as的) ? 分页查询 按雇员的id号升序取出 oracle的分页一共有三种方式 1.根据rowid来分 select * from t_xiaoxi where rowid in (select rid from (select rownum rn, rid from(select rowid rid, cid from t_xiaoxi order by cid desc) where rownum<10000) where rn>9980) order by cid desc; 执行时间0.03秒 2.按分析函数来分 select * from (select t.*, row_number() over(order by cid desc) rk from t_xiaoxi t) where rk<10000 and rk>9980; 执行时间1.01秒 3.按rownum来分
Oracle 笔记
12
select * from (select t.*,rownum rn from(select * from t_xiaoxi order by cid desc)t where rownum<10000) where rn>9980; 执行时间0.1秒 其中t_xiaoxi为表名称,cid为表的关键字段,取按cid降序排序后的第9981-9999条记录,t_xiaoxi表有70000多条记录。 我的感受1的效率最好,3次之,2最差。 //测试经过的分页查询okokok select * from (select a1.*, rownum rn from(select ename,job from emp) a1 where rownum<=10)where rn>=5; 下面最主要介绍第三种:按rownum来分 1. rownum 分页 SELECT * FROM emp; 2. 显示rownum[oracle分配的] SELECT e.*, ROWNUM rn FROM (SELECT * FROM emp) e; rn至关于Oracle分配的行的ID号 3.挑选出6—10条记录 先查出1-10条记录 SELECT e.*, ROWNUM rn FROM (SELECT * FROM emp) e WHERE ROWNUM <= 10; 若是后面加上rownum>=6是不行的, 4. 而后查出6-10条记录 SELECT * FROM (SELECT e.*, ROWNUM rn FROM (SELECT * FROM emp) e WHERE ROWNUM <= 10) WHERE rn >= 6; 5. 几个查询变化 a. 指定查询列,只须要修改最里层的子查询 只查询雇员的编号和工资 SELECT * FROM (SELECT e.*, ROWNUM rn FROM (SELECT ename, sal FROM emp) e WHERE ROWNUM <= 10) WHERE rn >= 6; b. 排序查询,只须要修改最里层的子查询 工资排序后查询6-10条数据 SELECT * FROM (SELECT e.*, ROWNUM rn FROM (SELECT ename, sal FROM emp ORDER by sal) e WHERE ROWNUM <= 10) WHERE rn >= 6; ? 用查询结果建立新表 这个命令是一种快捷的建表方式 CREATE TABLE mytable (id, name, sal, job, deptno) as SELECT empno, ename, sal, job, deptno FROM emp; 建立好以后,desc mytable;和select * from mytable;看看结果如何? 合并查询 ? 合并查询 有时在实际应用中,为了合并多个select语句的结果,能够使用集合操做符号union,union all,intersect,minus 多用于数据量比较大的数据局库,运行速度快。 1). union 该操做符用于取得两个结果集的并集。当使用该操做符时,会自动去掉结果集中重复行。 SELECT ename, sal, job FROM emp WHERE sal >2500 UNION SELECT ename, sal, job FROM emp WHERE job = 'MANAGER'; 2).union all 该操做符与union类似,可是它不会取消重复行,并且不会排序。 SELECT ename, sal, job FROM emp WHERE sal >2500 UNION ALL SELECT ename, sal, job FROM emp WHERE job = 'MANAGER';
Oracle 笔记
13
该操做符用于取得两个结果集的并集。当使用该操做符时,会自动去掉结果集中重复行。 3). intersect 使用该操做符用于取得两个结果集的交集。 SELECT ename, sal, job FROM emp WHERE sal >2500 INTERSECT SELECT ename, sal, job FROM emp WHERE job = 'MANAGER'; 4). minus 使用改操做符用于取得两个结果集的差集,他只会显示存在第一个集合中,而不存在第二个集合中的数据。 SELECT ename, sal, job FROM emp WHERE sal >2500 MINUS SELECT ename, sal, job FROM emp WHERE job = 'MANAGER'; (MINUS就是减法的意思) 建立数据库有两种方法: 1). 经过oracle提供的向导工具。√ database Configuration Assistant 【数据库配置助手】 2).咱们能够用手工步骤直接建立。
7.java操做oracle 内容介绍 1.上节回顾 2.java程序如何操做oracle √ 3.如何在oracle中操做数据 4.oracle事务处理 5.sql函数的使用 √ 指望目标 1.掌握oracle表对数据操做技巧 2.掌握在java程序中操做oracle 3.理解oracle事物概念 4.掌握oracle各类sql函数 java链接oracle ? 介绍 前面咱们一直在plsql中操做oracle,那么如何在java 程序中操做数据库呢? 下面咱们举例说明,写一个java,分页显示emp表的用户信息。
package com.sp;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
//演示 如何使用 jdbc_odbc桥链接方式
public class TestOracle {
public static void main(String[] args) {
try {
// 1.加载驱动
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Oracle 笔记
14
// 2.获得链接
Connection ct = DriverManager.getConnection(
"jdbc.odbc:testConnectOracle", "scott",
"tiger");
// 从下面开始,和SQL Server如出一辙
Statement sm = ct.createStatement();
ResultSet rs = sm.executeQuery("select * from emp");
while (rs.next()) {
//用户名
System.out.println("用户名: "+rs.getString(2));
//默认是从1开始编号的
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
在获得链接那里,要去配置数据源,点击控制面板-->系统和安全-->管理工具-->数据源(ODBC), 打开后点添加,如图: 能够看到,有个Oracle in OraDb10g_home1的驱动,它是Oracle安装完后自动加上去的。 选中 后,点完成,再填以下信息,如图: 这样配好后基本就能够了,但为了安全起见,建议你们测试一下,点击 Test Connection按钮, 测试经过后点ok,而后数据源就生成了,如图: 而后把数据源名称写进jdbc.odbc:???里。 这里要注意:jdbcodbc能不能远程链接呢?不能远程链接,也就是你这样写的话就意味着java程 序和oracle数据库应该是在同一台机器上,由于这里没有指定IP地址,确定默认就是本地。 如 果要远程连,就用jdbc,jdbc是能够远程连的。 运行TestOracle.java,控制台输出....................... 惋惜我没运行成功,说 java.sql.SQLException: No suitable driver found for jdbc.odbc:testConnectOracle at java.sql.DriverManager.getConnection(Unknown Source) at java.sql.DriverManager.getConnection(Unknown Source) at com.sp.TestOracle.main(TestOracle.java:18) 不知道为何。。。 接下来说解用JDBC的方式链接Oracle
package com.sp;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
//使用 jdbc链接oracle
public class TestOracle2 {
public static void main(String[] args) {
try {
// 1.加载驱动
Oracle 笔记
15
Class.forName("oracle.jdbc.driver.OracleDriver");
// 2.获得链接
Connection ct = DriverManager.getConnection
("jdbc:oracle:thin:@127.0.0.1:1521:orcl", "scott", "tiger");
// 从下面开始,和SQL Server如出一辙
Statement sm = ct.createStatement();
ResultSet rs = sm.executeQuery("select * from emp");
while (rs.next()) {
//用户名
System.out.println("用户名: "+rs.getString(2));
//默认是从1开始编号的
}
} catch (Exception e) {
e.printStackTrace();
}
}
} 记得要把驱动包引入,classes12.jar 运行,。。。。 再次惋惜,我仍是没运行成功,错误是: java.sql.SQLException: Io 异常: The Network Adapter could not establish the connection at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134) at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:179) at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:334) at oracle.jdbc.driver.OracleConnection.<init>(OracleConnection.java:418) at oracle.jdbc.driver.OracleDriver.getConnectionInstance (OracleDriver.java:521) at oracle.jdbc.driver.OracleDriver.connect(OracleDriver.java:325) at java.sql.DriverManager.getConnection(Unknown Source) at java.sql.DriverManager.getConnection(Unknown Source) at com.sp.TestOracle2.main(TestOracle2.java:18) 我也不知道为何。。。 幽怨了。。 接下来建个web project,来测试oracle的分页,挺麻烦,不记录了。。 在oracle中操做数据 - 使用特定格式插入日期值 ? 使用 to_date函数 请你们思考: 如何插入列带有日期的表,并按照年-月-日的格式插入? insert into emp values (9998, 'xiaohong', 'MANAGER', 7782, to_date('1988-12- 12', 'yyyy-mm-dd'), 78.9, 55.33, 10); 注意: insert into emp values (9998, 'xiaohong', 'MANAGER', 7782, '12-12月-1988', 78.9, 55.33, 10); 这句语句是能够成功运行的 使用子查询插入数据 ? 介绍 当使用valus子句时,一次只能插入一行数据,当使用子查询插入数据时,一条inset语句能够插
Oracle 笔记
16
入大量的数据。当处理行迁移或者装载外部表的数据到数据库时,能够使用子查询来插入数据。 把emp表中10号部门的数据导入到新表中 create table kkk(myId number(4), myName varchar2(50), myDept number(5)); insert into kkk (myId, myName, myDept) select empno, ename, deptno from emp where deptno = 10; ? 介绍 使用update语句更新数据时,既能够使用表达式或者数值直接修改数据,也能够使用子查询修改 数据。 问题:但愿员工SCOTT的岗位、工资、补助与SMITH员工同样。 update emp set(job, sal, comm)=(select job, sal, comm from emp where ename='SMITH') where ename='SCOTT';
8.oracle中事务处理
? 什么是事务 事务用于保证数据的一致性,它由一组相关的dml语句组成,该组的dml(数据操做语言,增删改,没有查询)语句要么所有成功,要么所有失败。 如:网上转帐就是典型的要用事务来处理,用于保证数据的一致性。 dml 数据操做语言 银行转帐、QQ申请、车票购买 ? 事务和锁 当执行事务操做时(dml语句),oracle会在被做用的表上加锁,防止其它用户修改表的结构。这里对咱们的用户来来说是很是重要的。 .....其它进程排序,知道1号进程完成,锁打开,2号进程进入。依次进行,若是有进程级别较高的,能够插队。 ? 提交事务 当执行用commit语句能够提交事务。当执行了commit语句以后,会确认事务的变化、结束事务。删除保存点、释放锁,当使用commit语句结束事务以后,其它会话将能够查看到事务变化后的新数据。 保存点就是为回退作的。保存点的个数没有限制 ? 回退事务 在介绍回退事务前,咱们先介绍一下保存点(savepoint)的概念和做用。保存点是事务中的一点。用于取消部分事务,当结束事务时,会自动的删除该事务所定义的全部保存点。当执行rollback时,经过指定保存点能够回退到指定的点,这里咱们做图说明。 ? 事务的几个重要操做 1.设置保存点 savepoint a 2.取消部分事务 rollback to a 3.取消所有事务 rollback 注意:这个回退事务,必须是没有commit前使用的;若是事务提交了,那么不管你刚才作了多少个保存点,都通通没有。 若是没有手动执行commit,而是exit了,那么会自动提交 ? java程序中如何使用事务 在java操做数据库时,为了保证数据的一致性,好比帐户操做(1)从一个帐户中减掉10$(2)在另外一个帐户上加入10$,咱们看看如何使用事务?
package com.sp;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
Oracle 笔记
17
import java.sql.Statement;
public class TestTrans {
public static void main(String[] args) {
try {
// 1.加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
// 2.获得链接
Connection ct = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "scott", "tiger");
Statement sm = ct.createStatement();
// 从scott的sal中减去100
sm.executeUpdate("update emp set sal=sal-100 where ename='SCOTT'");
int i = 7 / 0;
// 给smith的sal加上100
sm.executeUpdate("update emp set sal=sal+100 where ename='SMITH'");
// 关闭打开的资源
sm.close();
ct.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行,会出现异常,查看数据库,SCOTT的sal减了100,可是SMITH的sal却不变,很可怕。。。 咱们怎样才能保证,这两个操做要么同时成功,要么同时失败呢?
package com.sp;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class TestTrans {
public static void main(String[] args) {
Connection ct = null;
try {
// 1.加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
// 2.获得链接
ct = DriverManager.getConnection(
"jdbc:oracle:thin:@127.0.0.1:1521:orcl", "scott", "tiger");
// 加入事务处理
ct.setAutoCommit(false);// 设置不能默认提交
Statement sm = ct.createStatement();
// 从scott的sal中减去100
sm.executeUpdate("update emp set sal=sal-100 where ename='SCOTT'");
int i = 7 / 0;
Oracle 笔记
18
// 给smith的sal加上100
sm.executeUpdate("update emp set sal=sal+100 where ename='SMITH'");
// 提交事务
ct.commit();
// 关闭打开的资源
sm.close();
ct.close();
} catch (Exception e) {
// 若是发生异常,就回滚
try {
ct.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
再运行一下,会出现异常,查看数据库,数据没变化。。 ? 只读事务 只读事务是指只容许执行查询的操做,而不容许执行任何其它dml操做的事务,使用只读事务能够确保用户只能取得某时间点的数据。假定机票代售点天天18点开始统计今天的销售状况,这时能够使用只读事务。在设置了只读事务后,尽管其它会话可能会提交新的事务,可是只读事务将不会取得最新数据的变化,从而能够保证取得特定时间点的数据信息。 ? 设置只读事务 set transaction read only;
9.oracle的函数
sql函数的使用 字符函数? 介绍 字符函数是oracle中最经常使用的函数,咱们来看看有哪些字符函数: ? lower(char):将字符串转化为小写的格式。 ? upper(char):将字符串转化为大写的格式。 ? length(char):返回字符串的长度。 ? substr(char,m,n):取字符串的子串 n表明取n个的意思,不是表明取到第n个 ? replace(char1,search_string,replace_string) ? instr(char1,char2,[,n[,m]])取子串在字符串的位置 问题:将全部员工的名字按小写的方式显示 SQL> select lower(ename) from emp; 问题:将全部员工的名字按大写的方式显示。 SQL> select upper(ename) from emp; 问题:显示正好为5个字符的员工的姓名。 SQL> select * from emp where length(ename)=5; 问题:显示全部员工姓名的前三个字符。
Oracle 笔记
19
SQL> select substr(ename,1,3) from emp; 问题:以首字母大写,后面小写的方式显示全部员工的姓名。 SQL> select upper(substr(ename,1,1)) || lower(substr(ename,2,length(ename)-1)) from emp; 问题:以首字母小写,后面大写的方式显示全部员工的姓名。 SQL> select lower(substr(ename,1,1)) || upper(substr(ename,2,length(ename)-1)) from emp; 问题:显示全部员工的姓名,用“我是老虎”替换全部“A” SQL> select replace(ename,'A', '我是老虎') from emp; 数学函数? 介绍 数学函数的输入参数和返回值的数据类型都是数字类型的。数学函数包括cos,cosh,exp,ln, log,sin,sinh,sqrt,tan,tanh,acos,asin,atan,round,咱们讲最经常使用的: ? round(n,[m]) 该函数用于执行四舍五入,若是省掉m,则四舍五入到整数,若是m是正数,则四舍五入到小数点的m位后。若是m是负数,则四舍五入到小数点的m位前。 ? trunc(n,[m]) 该函数用于截取数字。若是省掉m,就截去小数部分,若是m是正数就截取到小数点的m位后,若是m是负数,则截取到小数点的前m位。 ? mod(m,n) ? floor(n) 返回小于或是等于n的最大整数 ? ceil(n) 返回大于或是等于n的最小整数 对数字的处理,在财务系统或银行系统中用的最多,不一样的处理方法,对财务报表有不一样的结果。 问题:显示在一个月为30天的状况下,全部员工的日薪金,忽略余数。 SQL> select trunc(sal/30), ename from emp; or SQL> select floor(sal/30), ename from emp; 在作oracle测试的时候,能够使用dual表 select mod(10,2) from dual;结果是0 select mod(10,3) from dual;结果是1 其它的数学函数,有兴趣的同窗能够本身去看看: abs(n): 返回数字n的绝对值 select abs(-13) from dual; acos(n): 返回数字的反余弦值 asin(n): 返回数字的反正弦值 atan(n): 返回数字的反正切值 cos(n): exp(n): 返回e的n次幂 log(m,n): 返回对数值 power(m,n): 返回m的n次幂 日期函数? 介绍 日期函数用于处理date类型的数据。 默认状况下日期格式是dd-mon-yy 即12-7月-78 (1)sysdate: 该函数返回系统时间 (2)add_months(d,n) (3)last_day(d):返回指定日期所在月份的最后一天 问题:查找已经入职8个月多的员工 SQL> select * from emp where sysdate>=add_months(hiredate,8); 问题:显示满10年服务年限的员工的姓名和受雇日期。
Oracle 笔记
20
SQL> select ename, hiredate from emp where sysdate>=add_months(hiredate,12*10); 问题:对于每一个员工,显示其加入公司的天数。 SQL> select floor(sysdate-hiredate) "入职天数",ename from emp; or SQL> select trunc(sysdate-hiredate) "入职天数",ename from emp; 问题:找出各月倒数第3天受雇的全部员工。 SQL> select hiredate,ename from emp where last_day(hiredate)-2=hiredate; 转换函数 ? 介绍√ 转换函数用于将数据类型从一种转为另一种。在某些状况下,oracle server容许值的数据类型和实际的不同,这时oracle server会隐含的转化数据类型 好比: create table t1(id int); insert into t1 values('10');-->这样oracle会自动的将'10' -->10 create table t2 (id varchar2(10)); insert into t2 values(1); -->这样oracle就会自动的将1 -->'1'; 咱们要说的是尽管oracle能够进行隐含的数据类型的转换,可是它并不适应全部的状况,为了提升程序的可靠性,咱们应该使用转换函数进行转换。 ? to_char 你能够使用select ename, hiredate, sal from emp where deptno = 10;显示信息,但是,在某些状况下,这个并不能知足你的需求。 问题:日期是否能够显示 时/分/秒 SQL> select ename, to_char(hiredate, 'yyyy-mm-dd hh24:mi:ss') from emp; 问题:薪水是否能够显示指定的货币符号 SQL> yy:两位数字的年份 2004-->04 yyyy:四位数字的年份 2004年 mm:两位数字的月份 8月-->08 dd:两位数字的天 30号-->30 hh24: 8点-->20 hh12:8点-->08 mi、ss-->显示分钟\秒 9:显示数字,并忽略前面0 0:显示数字,如位数不足,则用0补齐 .:在指定位置显示小数点 ,:在指定位置显示逗号 $:在数字前加美圆 L:在数字前面加本地货币符号 C:在数字前面加国际货币符号 G:在指定位置显示组分隔符、 D:在指定位置显示小数点符号(.) 问题:显示薪水的时候,把本地货币单位加在前面 SQL> select ename, to_char(hiredate, 'yyyy-mm-dd hh24:mi:ss'), to_char(sal,'L99999.99') from emp; 问题:显示1980年入职的全部员工 SQL> select * from emp where to_char(hiredate, 'yyyy')=1980;
Oracle 笔记
21
问题:显示全部12月份入职的员工 SQL> select * from emp where to_char(hiredate, 'mm')=12; ? to_date 函数to_date用于将字符串转换成date类型的数据。 问题:可否按照中国人习惯的方式年—月—日添加日期。 系统函数 ? sys_context 1)terminal:当前会话客户所对应的终端的标示符 2)lanuage: 语言 3)db_name: 当前数据库名称 4)nls_date_format: 当前会话客户所对应的日期格式 5)session_user: 当前会话客户所对应的数据库用户名 6)current_schema: 当前会话客户所对应的默认方案名 7)host: 返回数据库所在主机的名称 经过该函数,能够查询一些重要信息,好比你正在使用哪一个数据库? select sys_context('USERENV','db_name') from dual; 注意:USERENV是固定的,不能改的,db_name能够换成其它,好比select sys_context('USERENV','lanuage') from dual;又好比select sys_context('USERENV','current_schema') from dual;
10.数据库管理,表的逻辑备份与恢复
内容介绍 1.上节回顾 2.数据库管理员 3.数据库(表)的逻辑备份与恢复 √ 4.数据字典和动态性能视图 √ 5.管理表空间和数据文件 √ 指望目标 1.了解oracle管理员的基本职责 2.掌握备份和恢复数据库/表的方法 3.理解表空间、数据字典、性能视图 数据库管理员 ? 介绍 每一个oracle数据库应该至少有一个数据库管理员(dba),对于一个小的数据库,一个dba就够了,可是对于一个大的数据库可能须要多个dba分担不一样的管理职责。那么一个数据库管理员的主要工做是什么呢: ? 职责 1.安装和升级oracle数据库 2.建库,表空间,表,视图,索引? 3.制定并实施备份和恢复计划 4.数据库权限管理,调优,故障排除 5.对于高级dba,要求能参与项目开发,会编写sql语句、存储过程、触发器、规则、约束、包 ? 管理数据库的用户主要是sys和system (sys好像是董事长,system好像是总经理,董事长比总经理大,可是一般是总经理干事) 在前面咱们已经提到这两个用户,区别主要是: 1.最重要的区别,存储的数据的重要性不一样
Oracle 笔记
22
sys:全部oracle的数据字典的基表和视图都存放在sys用户中,这些基表和视图对于oracle的运行是相当重要的,由数据库本身维护,任何用户都不能手动更改。sys用户拥有dba,sysdba,sysoper角色或权限,是oracle权限最高的用户。 system:用于存放次一级的内部数据,如oracle的一些特性或工具的管理信息。system用户拥有dba,sysdba角色或系统权限。 看图: sysdba能够建数据库,sysope不能建数据库 2. 其次的区别,权限的不一样。 sys用户必须以as sysdba或as sysoper形式登陆。不能以normal方式登陆数据库 system若是正常登陆,它其实就是一个普通的dba用户,可是若是以as sysdba登陆,其结果实际上它是做为sys用户登陆的,从登陆信息里面咱们能够看出来。 sysdba和sysoper权限区别图,看图: sysdba>sysoper>dba 能够看到:只要是sysoper拥有的权限,sysdba都有;蓝色是它们区别的地方。(它们的最大区别是:sysdba能够建立数据库,sysoper不能够建立数据库) ? dba权限的用户 dba用户是指具备dba角色的数据库用户。特权用户能够执行启动实例,关闭实例等特殊操做,而dba用户只有在启动数据库后才能执行各类管理工做。 (至关于说dba连startup和shutdown这两个权限都没有) 两个主要的用户,三个重要权限,他们的区别和联系,你们要弄清楚 管理初始化参数 ? 管理初始化参数(调优的一个重要知识点,凭什么能够对数据库进行调优呢?是由于它能够对数据库的一些参数进行修改修正) 初始化参数用于设置实例或是数据库的特征。oracle9i提供了200多个初始化参数,而且每一个初始化参数都有默认值。 ? 显示初始化参数 (1) show parameter命令 ? 如何修改参数 须要说明的若是你但愿修改这些初始化的参数,能够到文件D:\oracle\admin\myoral\pfile\init.ora文件中去修改好比要修改实例的名字 数据库(表)的逻辑备份与恢复 介绍 ? 介绍 逻辑备份是指使用工具export将数据对象的结构和数据导出到文件的过程,逻辑恢复是指当数据库对象被误操做而损坏后使用工具import利用备份的文件把数据对象导入到数据库的过程。 物理备份便可在数据库open的状态下进行也可在关闭数据库后进行,可是逻辑备份和恢复只能在open的状态下进行。 看图: ? 导出 导出具体的分为:导出表,导出方案,导出数据库三种方式。 导出使用exp命令来完成的,该命令经常使用的选项有: userid: 用于指定执行导出操做的用户名,口令,链接字符串 tables: 用于指定执行导出操做的表 owner: 用于指定执行导出操做的方案 full=y: 用于指定执行导出操做的数据库 inctype: 用于指定执行导出操做的增量类型 rows: 用于指定执行导出操做是否要导出表中的数据 file: 用于指定导出文件名
Oracle 笔记
23
? 导出表 1.导出本身的表 exp userid=scott/tiger@myoral tables=(emp,dept) file=d:\e1.dmp 2.导出其它方案的表 若是用户要导出其它方案的表,则须要dba的权限或是exp_full_database的权限,好比system就能够导出scott的表 E:\oracle\ora92\bin>exp userid=system/manager@myoral tables=(scott.emp) file=d:\e2.emp 特别说明:在导入和导出的时候,要到oracle目录的bin目录下。 3. 导出表的结构 exp userid=scott/tiger@accp tables=(emp) file=d:\e3.dmp rows=n 4. 使用直接导出方式 exp userid=scott/tiger@accp tables=(emp) file=d:\e4.dmp direct=y 这种方式比默认的常规方式速度要快,当数据量大时,能够考虑使用这样的方法。 这时须要数据库的字符集要与客户端字符集彻底一致,不然会报错... ? 导出方案 导出方案是指使用export工具导出一个方案或是多个方案中的全部对象(表,索引,约束...)和数据。并存放到文件中。 1. 导出本身的方案 exp userid=scott/tiger@myorcl owner=scott file=d:\scott.dmp 2. 导出其它方案 若是用户要导出其它方案,则须要dba的权限或是exp_full_database的权限,好比system用户就能够导出任何方案 exp userid=system/manager@myorcl owner=(system,scott) file=d:\system.dmp ? 导出数据库 导出数据库是指利用export导出全部数据库中的对象及数据,要求该用户具备dba的权限或者是exp_full_database权限 增量备份(好处是第一次备份后,第二次备份就快不少了) exp userid=system/manager@myorcl full=y inctype=complete file=d:\all.dmp 导入 ? 介绍 导入就是使用工具import将文件中的对象和数据导入到数据库中,可是导入要使用的文件必须是export所导出的文件。与导出类似,导入也分为导入表,导入方案,导入数据库三种方式。 imp经常使用的选项有 userid: 用于指定执行导入操做的用户名,口令,链接字符串 tables: 用于指定执行导入操做的表 formuser: 用于指定源用户 touser: 用于指定目标用户 file: 用于指定导入文件名 full=y: 用于指定执行导入整个文件 inctype: 用于指定执行导入操做的增量类型 rows: 指定是否要导入表行(数据) ignore: 若是表存在,则只导入数据 ? 导入表 1. 导入本身的表 imp userid=scott/tiger@myorcl tables=(emp) file=d:\xx.dmp 2. 导入表到其它用户 要求该用户具备dba的权限,或是imp_full_database imp userid=system/tiger@myorcl tables=(emp) file=d:\xx.dmp touser=scott 3. 导入表的结构
Oracle 笔记
24
只导入表的结构而不导入数据 imp userid=scott/tiger@myorcl tables=(emp) file=d:\xx.dmp rows=n 4. 导入数据 若是对象(如比表)已经存在能够只导入表的数据 imp userid=scott/tiger@myorcl tables=(emp) file=d:\xx.dmp ignore=y ? 导入方案 导入方案是指使用import工具将文件中的对象和数据导入到一个或是多个方案中。若是要导入其它方案,要求该用户具备dba的权限,或者imp_full_database 1. 导入自身的方案 imp userid=scott/tiger file=d:\xxx.dmp 2. 导入其它方案 要求该用户具备dba的权限 imp userid=system/manager file=d:\xxx.dmp fromuser=system touser=scott ? 导入数据库 在默认状况下,当导入数据库时,会导入全部对象结构和数据,案例以下: imp userid=system/manager full=y file=d:\xxx.dmp
11.数据字典和动态性能视图 介绍:数据字典是什么 数据字典是oracle数据库中最重要的组成部分,它提供了数据库的一些系统信息。 动态性能视图记载了例程启动后的相关信息。 ? 数据字典 数据字典记录了数据库的系统信息,它是只读表和视图的集合,数据字典的全部者为sys用户。 用户只能在数据字典上执行查询操做(select语句),而其维护和修改是由系统自动完成的。 这里咱们谈谈数据字典的组成:数据字典包括数据字典基表和数据字典视图,其中基表存储数据库的基本信息,普通用户不能直接访问数据字典的基表。数据字典视图是基于数据字典基表所创建的视图,普通用户能够经过查询数据字典视图取得系统信息。数据字典视图主要包括user_xxx,all_xxx,dba_xxx三种类型。 ? user_tables; 用于显示当前用户所拥有的全部表,它只返回用户所对应方案的全部表 好比:select table_name from user_tables; ? all_tables; 用于显示当前用户能够访问的全部表,它不只会返回当前用户方案的全部表,还会返回当前用户能够访问的其它方案的表: 好比:select table_name from all_tables; ? dba_tables; 它会显示全部方案拥有的数据库表。可是查询这种数据库字典视图,要求用户必须是dba角色或是有select any table系统权限。 例如:当用system用户查询数据字典视图dba_tables时,会返回system,sys,scott...方案所对应的数据库表。 ? 用户名,权限,角色 在创建用户时,oracle会把用户的信息存放到数据字典中,当给用户授予权限或是角色时,oracle会将权限和角色的信息存放到数据字典。 经过查询dba_users能够显示全部数据库用户的详细信息; 经过查询数据字典视图dba_sys_privs,能够显示用户所具备的系统权限; 经过查询数据字典视图dba_tab_privs,能够显示用户具备的对象权限; 经过查询数据字典dba_col_privs能够显示用户具备的列权限; 经过查询数据库字典视图dba_role_privs能够显示用户所具备的角色。
Oracle 笔记
25
这里给你们再讲讲角色和权限的关系。 例如:要查看scott具备的角色,可查询dba_role_privs; SQL> select * from dba_role_privs where grantee='SCOTT'; //查询orale中全部的系统权限,通常是dba select * from system_privilege_map order by name; //查询oracle中全部对象权限,通常是dba select distinct privilege from dba_tab_privs; //查询oracle中全部的角色,通常是dba select * from dba_roles; //查询数据库的表空间 select tablespace_name from dba_tablespaces; 问题1:如何查询一个角色包括的权限? a.一个角色包含的系统权限 select * from dba_sys_privs where grantee='角色名' 另外也能够这样查看: select * from role_sys_privs where role='角色名' b.一个角色包含的对象权限 select * from dba_tab_privs where grantee='角色名' 问题2:oracle究竟有多少种角色? SQL> select * from dba_roles; 问题3:如何查看某个用户,具备什么样的角色? select * from dba_role_privs where grantee='用户名' ? 显示当前用户能够访问的全部数据字典视图。 select * from dict where comments like '%grant%'; ? 显示当前数据库的全称 select * from global_name; ? 其它说明 数据字典记录有oracle数据库的全部系统信息。经过查询数据字典能够取得如下系统信息:好比 1.对象定义状况 2.对象占用空间大小 3.列信息 4.约束信息 ... 可是由于这些个信息,能够经过pl/sql developer工具查询获得,因此这里我就飘过。 ? 动态性能视图 动态性能视图用于记录当前例程的活动信息,当启动oracle server时,系统会创建动态性能视图;当中止oracle server时,系统会删除动态性能视图。oracle的全部动态性能视图都是以v_$开始的,而且oracle为每一个动态性能视图都提供了相应的同义词,而且其同义词是以V$开始的,例如v_$datafile的同义词为v$datafile;动态性能视图的全部者为sys,通常状况下,由dba或是特权用户来查询动态性能视图。 由于这个在实际中用的较少,因此飞过。
12.数据库管理 -- 管理表空间和数据文件 ? 介绍 表空间是数据库的逻辑组成部分。从物理上讲,数据库数据存放在数据文件中;从逻辑上讲,数据库则是存放在表空间中,表空间由一个或多个数据文件组成。
Oracle 笔记
26
数据库的逻辑结构 ? 介绍 oracle中逻辑结构包括表空间、段、区和块。 说明一下数据库由表空间构成,而表空间又是由段构成,而段又是由区构成,而区又是由oracle块构成的这样的一种结构,能够提升数据库的效率。 为了让你们明白,咱们画图说明逻辑关系:看图: 表空间 ? 介绍 表空间用于从逻辑上组织数据库的数据。数据库逻辑上是由一个或是多个表空间组成的。经过表空间能够达到如下做用: 1. 控制数据库占用的磁盘空间 2. dba能够将不一样数据类型部署到不一样的位置,这样有利于提升i/o性能,同时利于备份和恢复等管理操做。 ? 创建表空间 创建表空间是使用crate tablespace命令完成的,须要注意的是,通常状况下,创建表空间是特权用户或是dba来执行的,若是用其它用户来建立表空间,则用户必需要具备create tablespace的系统权限。 ? 创建数据表空间 在创建数据库后,为便于管理表,最好创建本身的表空间 create tablespace data01 datafile 'd:\test\dada01.dbf' size 20m uniform size 128k; 说明:执行完上述命令后,会创建名称为data01的表空间,并为该表空间创建名称为data01.dbf的数据文件,区的大小为128k ? 使用数据表空间 create table mypart(deptno number(4), dname varchar2(14), loc varchar2(13)) tablespace data01; ? 改变表空间的状态 当创建表空间时,表空间处于联机的(online)状态,此时该表空间是能够访问的,而且该表空间是能够读写的,便可以查询该表空间的数据,并且还能够在表空间执行各类语句。可是在进行系统维护或是数据维护时,可能须要改变表空间的状态。通常状况下,由特权用户或是dba来操做。 1. 使表空间脱机 alter tablespace 表空间名 offline; 2. 使表空间联机 alter tablespace 表空间名 online; 3. 只读表空间 当创建表空间时,表空间能够读写,若是不但愿在该表空间上执行update,delete,insert操做,那么能够将表空间修改成只读 alter tablespace 表空间名 read only; (修改成可写是 alter tablespace 表空间名 read write;) ? 改变表空间的状态 咱们给你们举一个实例,说明只读特性: 1. 知道表空间名,显示该表空间包括的全部表 select * from all_tables where tablespace_name=’表空间名’; 2. 知道表名,查看该表属于那个表空间 select tablespace_name, table_name from user_tables where table_name=’emp’; 经过2.咱们能够知道scott.emp是在system这个表空间上,如今咱们能够将system改成只读的可是咱们不会成功,由于system是系统表空间,若是是普通表空间,那么咱们就能够将其设为只读的,给你们作一个演示,能够增强理解。 3. 4. 使表空间可读写 alter tablespace 表空间名 read write; ? 删除表空间
Oracle 笔记
27
通常状况下,由特权用户或是dba来操做,若是是其它用户操做,那么要求用户具备drop tablespace系统权限。 drop tablespace ‘表空间’ including contents and datafiles; 说明:including contents表示删除表空间时,删除该空间的全部数据库对象,而datafiles表示将数据库文件也删除。 ? 扩展表空间 表空间是由数据文件组成的,表空间的大小实际上就是数据文件相加后的大小。那么咱们能够想象,假定表employee存放到data01表空间上,初始大小就是2M,当数据满2M空间后,若是在向employee表插入数据,这样就会显示空间不足的错误。 案例说明: 1. 创建一个表空间 sp01 2. 在该表空间上创建一个普通表 mydment 其结构和dept同样 3. 向该表中加入数据 insert into mydment select * from dept; 4. 当必定时候就会出现没法扩展的问题,怎么办? 5. 就扩展该表空间,为其增长更多的存储空间。有三种方法: 1. 增长数据文件 SQL> alter tablespace sp01 add datafile ‘d:\test\sp01.dbf’ size 20m; 2. 增长数据文件的大小 SQL> alter tablespace 表空间名 ‘d:\test\sp01.dbf’ resize 20m; 这里须要注意的是数据文件的大小不要超过500m。 3. 设置文件的自动增加。 SQL> alter tablespace 表空间名 ‘d:\test\sp01.dbf’ autoextend on next 10m maxsize 500m; ? 移动数据文件 有时,若是你的数据文件所在的磁盘损坏时,该数据文件将不能再使用,为了可以从新使用,须要将这些文件的副本移动到其它的磁盘,而后恢复。 下面以移动数据文件sp01.dbf为例来讲明: 1. 肯定数据文件所在的表空间 select tablespace_name from dba_data_files where file_name=’d:\test\sp01.dbf’; 2. 使表空间脱机 确保数据文件的一致性,将表空间转变为offline的状态。 alter tablespace sp01(表空间名) offline; 3. 使用命令移动数据文件到指定的目标位置 host move d:\test\sp01.dbf c:\test\sp01.dbf 4. 执行alter tablespace命令 在物理上移动了数据后,还必须执行alter tablespace命令对数据库文件进行逻辑修改: alter tablespace sp01 rename datafile ‘d:\test\sp01.dbf’ to ‘c:\test\sp01.dbf’; 5. 使得表空间联机 在移动了数据文件后,为了使用户能够访问该表空间,必须将其转变为online状态。 alter tablespace sp01(表空间名) online; ? 显示表空间信息 查询数据字典视图dba_tablespaces,显示表空间的信息: select tablespace_name from dba_tablespaces; ? 显示表空间所包含的数据文件 查询数据字典视图dba_data_files,可显示表空间所包含的数据文件,以下: select file_name, bytes from dba_data_files where tablespce_name=’表空间’; ? 表空间小结 1. 了解表空间和数据文件的做用
Oracle 笔记
28
2. 掌握经常使用表空间,undo表空间和临时表空间的创建方法 3. 了解表空间的各个状态(online, offline, read write, read only)的做用,及如何改变表空间的状态的方法。 4. 了解移动数据文件的缘由,及使用alter tablespace 和alter datatable命令移动数据文件的方法。 ? 其它表空间 除了最经常使用的数据表空间外,还有其它类型表空间: 1. 索引表空间 2. undo表空间 3. 临时表空间 4. 非标准块的表空间 这几种表空间,你们伙能够本身参考书籍研究,这里我就不讲。 ? 其它说明 关于表空间的组成部分 段/区/块,咱们在后面给你们讲解。
13.约束 玩转oracle实战教程(第五天) 指望目标 1.掌握维护oracle数据完整性的技巧 2.理解索引概念,会创建索引 3.管理oracle的权限和角色 维护数据的完整性 ? 介绍 数据的完整性用于确保数据库数据听从必定的商业和逻辑规则,在oracle中,数据完整性能够使用约束、触发器、应用程序(过程、函数)三种方法来实现,在这三种方法中,由于约束易于维护,而且具备最好的性能,因此做为维护数据完整性的首选。 约束 ? 约束 约束用于确保数据库数据知足特定的商业规则。在oracle中,约束包括:not null、 unique, primary key, foreign key,和check五种。 使用 ? not null(非空) 若是在列上定义了not null,那么当插入数据时,必须为列提供数据。 ? unique(惟一) 当定义了惟一约束后,该列值是不能重复的,可是能够为null。 ? primary key(主键) 用于惟一的标示表行的数据,当定义主键约束后,该列不但不能重复并且不能为null。 须要说明的是:一张表最多只能有一个主键,可是能够有多个unqiue约束。 ? foreign key(外键) 用于定义主表和从表之间的关系。外键约束要定义在从表上,主表则必须具备主键约束或是unique约束,当定义外键约束后,要求外键列数据必须在主表的主键列存在或是为null。 ? check 用于强制行数据必须知足的条件,假定在sal列上定义了check约束,并要求sal列值在1000-2000之间若是不在1000-2000之间就会提示出错。 ? 商店售货系统表设计案例 现有一个商店的数据库,记录客户及其购物状况,由下面三个表组成:商品goods(商品号goodsId,商品名 goodsName,单价 unitprice,商品类别category,供应商provider); 客户customer(客户号customerId,姓名name,住在address,电邮email,性别sex,身份证cardId);
Oracle 笔记
29
购买purchase(客户号customerId,商品号goodsId,购买数量nums); 请用SQL语言完成下列功能: 1. 建表,在定义中要求声明: (1). 每一个表的主外键; (2). 客户的姓名不能为空值; (3). 单价必须大于0,购买数量必须在1到30之间; (4). 电邮不可以重复; (5). 客户的性别必须是 男 或者 女,默认是男; SQL> create table goods(goodsId char(8) primary key, --主键 goodsName varchar2(30), unitprice number(10,2) check(unitprice>0), category varchar2(8), provider varchar2(30) ); SQL> create table customer( customerId char(8) primary key, --主键 name varchar2(50) not null, --不为空 address varchar2(50), email varchar2(50) unique, sex char(2) default '男' check(sex in ('男','女')), -- 一个char能存半个汉字,两位char能存一个汉字 cardId char(18) ); SQL> create table purchase( customerId char(8) references customer(customerId), goodsId char(8) references goods(goodsId), nums number(10) check (nums between 1 and 30) ); 表是默认建在SYSTEM表空间的 维护 ? 商店售货系统表设计案例(2) 若是在建表时忘记创建必要的约束,则能够在建表后使用alter table命令为表增长约束。可是要注意:增长not null约束时,须要使用modify选项,而增长其它四种约束使用add选项。 1. 增长商品名也不能为空 SQL> alter table goods modify goodsName not null; 2. 增长身份证也不能重复 SQL> alter table customer add constraint xxxxxx unique(cardId); 3. 增长客户的住址只能是’海淀’,’朝阳’,’东城’,’西城’,’通州’,’崇文’,’昌平’; SQL> alter table customer add constraint yyyyyy check (address in (’海淀’,’朝阳’,’东城’,’西城’,’通州’,’崇文’,’昌平’)); ? 删除约束 当再也不须要某个约束时,能够删除。 alter table 表名 drop constraint 约束名称; 特别说明一下: 在删除主键约束的时候,可能有错误,好比: alter table 表名 drop primary key; 这是由于若是在两张表存在主从关系,那么在删除主表的主键约束时,必须带上cascade选项 如像:
Oracle 笔记
30
alter table 表名 drop primary key cascade; ? 显示约束信息 1.显示约束信息 经过查询数据字典视图user_constraints,能够显示当前用户全部的约束的信息。 select constraint_name, constraint_type, status, validated from user_constraints where table_name = '表名'; 2.显示约束列 经过查询数据字典视图user_cons_columns,能够显示约束所对应的表列信息。 select column_name, position from user_cons_columns where constraint_name = '约束名'; 3.固然也有更容易的方法,直接用pl/sql developer查看便可。简单演示一下下... 表级定义 列级定义 ? 列级定义 列级定义是在定义列的同时定义约束。 若是在department表定义主键约束 create table department4(dept_id number(12) constraint pk_department primary key, name varchar2(12), loc varchar2(12)); ? 表级定义 表级定义是指在定义了全部列后,再定义约束。这里须要注意: not null约束只能在列级上定义。 以在创建employee2表时定义主键约束和外键约束为例: create table employee2(emp_id number(4), name varchar2(15), dept_id number(2), constraint pk_employee primary key (emp_id), constraint fk_department foreign key (dept_id) references department4(dept_id));
14.Oracle索引、权限
管理索引-原理介绍 ? 介绍 索引是用于加速数据存取的数据对象。合理的使用索引能够大大下降i/o次数,从而提升数据访问性能。索引有不少种咱们主要介绍经常使用的几种: 为何添加了索引后,会加快查询速度呢? 建立索引 ? 单列索引 单列索引是基于单个列所创建的索引,好比: create index 索引名 on 表名(列名); ? 复合索引 复合索引是基于两列或是多列的索引。在同一张表上能够有多个索引,可是要求列的组合必须不一样,好比: create index emp_idx1 on emp (ename, job); create index emp_idx1 on emp (job, ename); 使用原则 ? 使用原则 1. 在大表上创建索引才有意义 2. 在where子句或是链接条件上常常引用的列上创建索引 3. 索引的层次不要超过4层 这里能不能给学生演示这个效果呢? 如何构建一个大表呢?
Oracle 笔记
31
索引的缺点 ? 索引缺点分析 索引有一些先天不足: 1. 创建索引,系统要占用大约为表1.2倍的硬盘和内存空间来保存索引。 2. 更新数据的时候,系统必需要有额外的时间来同时对索引进行更新,以维持数据和索引的一致性。 实践代表,不恰当的索引不但于事无补,反而会下降系统性能。由于大量的索引在进行插入、修改和删除操做时比没有索引花费更多的系统时间。 好比在以下字段创建索引应该是不恰当的: 1. 不多或从不引用的字段; 2. 逻辑型的字段,如男或女(是或否)等。 综上所述,提升查询效率是以消耗必定的系统资源为代价的,索引不能盲目的创建,这是考验一个DBA是否优秀的很重要的指标。 其它索引 ? 介绍 按照数据存储方式,能够分为B*树、反向索引、位图索引; 按照索引列的个数分类,能够分为单列索引、复合索引; 按照索引列值的惟一性,能够分为惟一索引和非惟一索引。 此外还有函数索引,全局索引,分区索引... 对于索引我还要说: 在不一样的状况,咱们会在不一样的列上创建索引,甚至创建不一样种类的索引,请记住,技术是死的,人是活的。好比: B*树索引创建在重复值不多的列上,而位图索引则创建在重复值不少、不一样值相对固定的列上。 显示索引信息 ? 显示表的全部索引 在同一张表上能够有多个索引,经过查询数据字典视图dba_indexs和user_indexs,能够显示索引信息。其中dba_indexs用于显示数据库全部的索引信息,而user_indexs用于显示当前用户的索引信息: select index_name, index_type from user_indexes where table_name = '表名'; ? 显示索引列 经过查询数据字典视图user_ind_columns,能够显示索引对应的列的信息 select table_name, column_name from user_ind_columns where index_name = 'IND_ENAME'; ? 你也能够经过pl/sql developer工具查看索引信息 管理权限和角色 介绍 ? 介绍 这一部分咱们主要看看oracle中如何管理权限和角色,权限和角色的区别在那里。 当刚刚创建用户时,用户没有任何权限,也不能执行任何操做。若是要执行某种特定的数据库操做,则必须为其授予系统的权限;若是用户要访问其它方案的对象,则必须为其授予对象的权限。为了简化权限的管理,能够使用角色。这里咱们会详细的介绍。看图: 权限 ? 权限 权限是指执行特定类型sql命令或是访问其它方案对象的权利,包括系统权限和对象权限两种。 系统权限 ? 系统权限介绍 系统权限是指执行特定类型sql命令的权利。它用于控制用户能够执行的一个或是一组数据库操做。好比当用户具备create table权限时,能够在其方案中建表,当用户具备create any table权限时,能够在任何方案中建表。oracle提供了100多种系统权限。
Oracle 笔记
32
经常使用的有: create session 链接数据库 create table 建表 create view 建视图 create public synonym 建同义词 create procedure 建过程、函数、包 create trigger 建触发器 create cluster 建簇 ? 显示系统权限 oracle提供了100多种系统权限,并且oracle的版本越高,提供的系统权限就越多,咱们能够查询数据字典视图system_privilege_map,能够显示全部系统权限。 select * from system_privilege_map order by name; ? 授予系统权限 通常状况,授予系统权限是由dba完成的,若是用其余用户来授予系统权限,则要求该用户必须具备grant any privilege的系统权限。在授予系统权限时,能够带有with admin option选项,这样,被授予权限的用户或是角色还能够将该系统权限授予其它的用户或是角色。为了让你们快速理解,咱们举例说明: 1.建立两个用户ken,tom。初始阶段他们没有任何权限,若是登陆就会给出错误的信息。 create user ken identfied by ken; 2 给用户ken受权 1). grant create session, create table to ken with admin option; 2). grant create view to ken; 3 给用户tom受权 咱们能够经过ken给tom受权,由于with admin option是加上的。固然也能够经过dba给tom受权,咱们就用ken给tom受权: 1. grant create session, create table to tom; 2. grant create view to ken; --ok吗?不ok ? 回收系统权限 通常状况下,回收系统权限是dba来完成的,若是其它的用户来回收系统权限,要求该用户必须具备相应系统权限及转授系统权限的选项(with admin option)。回收系统权限使用revoke来完成。 当回收了系统权限后,用户就不能执行相应的操做了,可是请注意,系统权限级联收回的问题?[不是级联回收!] system --------->ken ---------->tom (create session)(create session)( create session) 用system执行以下操做: revoke create session from ken; --请思考tom还能登陆吗? 答案:能,能够登陆 对象权限 ? 对象权限介绍 指访问其它方案对象的权利,用户能够直接访问本身方案的对象,可是若是要访问别的方案的对象,则必须具备对象的权限。 好比smith用户要访问scott.emp表(scott:方案,emp:表) 经常使用的有: alter 修改 delete 删除 select 查询 insert 添加 update 修改 index 索引 references 引用 execute 执行 ? 显示对象权限 经过数据字段视图能够显示用户或是角色所具备的对象权限。视图为dba_tab_privs SQL> conn system/manager; SQL> select distinct privilege from dba_tab_privs; SQL> select grantor, owner, table_name, privilege from dba_tab_privs where grantee = 'BLAKE';
Oracle 笔记
33
1.授予对象权限 在oracle9i前,授予对象权限是由对象的全部者来完成的,若是用其它的用户来操做,则须要用户具备相应的(with grant option)权限,从oracle9i开始,dba用户(sys,system)能够将任何对象上的对象权限授予其它用户。授予对象权限是用grant命令来完成的。 对象权限能够授予用户,角色,和public。在授予权限时,若是带有with grant option选项,则能够将该权限转授给其它用户。可是要注意with grant option选项不能被授予角色。 1.monkey用户要操做scott.emp表,则必须授予相应的对象权限 1). 但愿monkey能够查询scott.emp表的数据,怎样操做? grant select on emp to monkey; 2). 但愿monkey能够修改scott.emp的表数据,怎样操做? grant update on emp to monkey; 3). 但愿monkey能够删除scott.emp的表数据,怎样操做? grant delete on emp to monkey; 4). 有没有更加简单的方法,一次把全部权限赋给monkey? grant all on emp to monkey; 2.可否对monkey访问权限更加精细控制。(授予列权限) 1). 但愿monkey只能够修改scott.emp的表的sal字段,怎样操做? grant update on emp(sal) to monkey 2).但愿monkey只能够查询scott.emp的表的ename,sal数据,怎样操做? grant select on emp(ename,sal) to monkey ... 3.授予alter权限 若是black用户要修改scott.emp表的结构,则必须授予alter对象权限 SQL> conn scott/tiger SQL> grant alter on emp to blake; 固然也能够用system,sys来完成这件事。 4.授予execute权限 若是用户想要执行其它方案的包/过程/函数,则须有execute权限。 好比为了让ken能够执行包dbms_transaction,能够授予execute权限。 SQL> conn system/manager SQL> grant execute on dbms_transaction to ken; 5.授予index权限 若是想在别的方案的表上创建索引,则必须具备index对象权限。 若是为了让black能够在scott.emp表上创建索引,就给其index的对象权限 SQL> conn scott/tiger SQL> grant index on scott.emp to blake; 6.使用with grant option选项 该选项用于转授对象权限。可是该选项只能被授予用户,而不能授予角色 SQL> conn scott/tiger; SQL> grant select on emp to blake with grant option; SQL> conn black/shunping SQL> grant select on scott.emp to jones; ? 回收对象权限 在oracle9i中,收回对象的权限能够由对象的全部者来完成,也能够用dba用户(sys,system)来完成。 这里要说明的是:收回对象权限后,用户就不能执行相应的sql命令,可是要注意的是对象的权限是否会被级联收回?【级
Oracle 笔记
34
联回收】 如:scott------------->blake-------------->jones select on emp select on emp select on emp SQL> conn scott/tiger@accp SQL> revoke select on emp from blake 请你们思考,jones可否查询scott.emp表数据。 答案:查不了了(和系统权限不同,恰好相反)
15.角色
? 介绍 角色就是相关权限的命令集合,使用角色的主要目的就是为了简化权限的管理,假定有用户a,b,c为了让他们都拥有权限 1. 链接数据库 2. 在scott.emp表上select,insert,update。 若是采用直接受权操做,则须要进行12次受权。 由于要进行12次受权操做,因此比较麻烦喔!怎么办? 若是咱们采用角色就能够简化: 首先将creat session,select on scott.emp,insert on scott.emp, update on scott.emp授予角色,而后将该角色授予a,b,c用户,这样就能够三次受权搞定。 角色分为预约义和自定义角色两类: ? 预约义角色 预约义角色是指oracle所提供的角色,每种角色都用于执行一些特定的管理任务,下面咱们介绍经常使用的预约义角色connect,resource,dba 1.connect角色 connect角色具备通常应用开发人员须要的大部分权限,当创建了一个用户后,多数状况下,只要给用户授予connect和resource角色就够了,那么connect角色具备哪些系统权限呢? alter session create cluster create database link create session create table create view create sequence 2.resource角色 resource角色具备应用开发人员所须要的其它权限,好比创建存储过程,触发器等。这里须要注意的是resource角色隐含了unlimited tablespace系统权限。 resource角色包含如下系统权限: create cluster create indextype create table create sequence create type create procedure create trigger 3.dba角色
Oracle 笔记
35
dba角色具备全部的系统权限,及with admin option选项,默认的dba用户为sys和system,它们能够将任何系统权限授予其余用户。可是要注意的是dba角色不具有sysdba和sysoper的特权(启动和关闭数据库)。 ? 自定义角色 顾名思义就是本身定义的角色,根据本身的须要来定义。通常是dba来创建,若是用别的用户来创建,则须要具备create role的系统权限。在创建角色时能够指定验证方式(不验证,数据库验证等)。 1.创建角色(不验证) 若是角色是公用的角色,能够采用不验证的方式创建角色。 create role 角色名 not identified; 2.创建角色(数据库验证) 采用这样的方式时,角色名、口令存放在数据库中。当激活该角色时,必须提供口令。在创建这种角色时,须要为其提供口令。 create role 角色名 identified by 密码; 角色受权 当创建角色时,角色没有任何权限,为了使得角色完成特定任务,必须为其授予相应的系统权限和对象权限。 1.给角色受权 给角色授予权限和给用户受权没有太多区别,可是要注意,系统权限的unlimited tablespace和对象权限的with grant option选项是不能授予角色的。 SQL> conn system/manager; SQL> grant create session to 角色名 with admin option SQL> conn scott/tiger@myoral; SQL> grant select on scott.emp to 角色名; SQL> grant insert, update, delete on scott.emp to 角色名; 经过上面的步骤,就给角色受权了。 2.分配角色给某个用户 通常分配角色是由dba来完成的,若是要以其它用户身份分配角色,则要求用户必须具备grant any role的系统权限。 SQL> conn system/manager; SQL> grant 角色名 to blake with admin option; 由于我给了with admin option选项,因此,blake能够把system分配给它的角色分配给别的用户。 ? 删除角色 使用drop role,通常是dba来执行,若是其它用户则要求该用户具备drop any role系统权限。 SQL> conn system/manager; SQL> drop role 角色名; 问题:若是角色被删除,那么被授予角色的用户是否还具备以前角色里的权限? 答案:不具备了 ? 显示角色信息 1.显示全部角色 SQL> select * from dba_roles; 2.显示角色具备的系统权限 SQL> select privilege, admin_option from role_sys_privs where role='角色名'; 3.显示角色具备的对象权限 经过查询数据字典视图dba_tab_privs能够查看角色具备的对象权限或是列的权限。 4.显示用户具备的角色,及默认角色 当以用户的身份链接到数据库时,oracle会自动的激活默认的角色,经过查询数据字典视图dba_role_privs能够显示某个用户具备的全部角色及当前默认的角色
Oracle 笔记
36
SQL> select granted_role, default_role from dba_role_privs where grantee = ‘用户名’; ? 精细访问控制 精细访问控制是指用户能够使用函数,策略实现更加细微的安全访问控制。若是使用精细访问控制,则当在客户端发出sql语句(select,insert,update,delete)时,oracle会自动在sql语句后追加谓词(where子句),并执行新的sql语句,经过这样的控制,能够使得不一样的数据库用户在访问相同表时,返回不一样的数据信息,如: 用户 scott blake jones 策略 emp_access 数据库表 emp 如上图所示,经过策略emp_access,用户scott,black,jones在执行相同的sql语句时,能够返回不一样的结果。例如:当执行select ename from emp; 时,根据实际状况能够返回不一样的结果。
16.PL/SQL 块的结构和实例 韩顺平.玩转oralce第24讲.plsql编程(1) 玩转orcle实战教程(第六天) 内容介绍 1.上节回顾 2.pl/sql的介绍 √ 3.pl/sql的基础 √ 指望目标 1.理解oracle的pl/sql概念 2.掌握pl/sql编程技术(包括编写过程、函数、触发器...) pl/sql的介绍 pl/sql是什么 pl/sql(procedural language/sql)是oracle在标准的sql语言上的扩展。pl/sql不只容许嵌入sql语言,还能够定义变量和常量,容许使用条件语句和循环语句,容许使用例外处理各类错误,这样使得它的功能变得更增强大。 为何学pl/sql ? 学习必要性 1.提升应用程序的运行性能 2.模块化的设计思想【分页的过程,订单的过程,转帐的过程。。】 3.减小网络传输量 4.提升安全性(sql会包括表名,有时还可能有密码,传输的时候会泄露。PL/SQL就不会) 为何PL/SQL会快呢?看图: 很差的地方: 移植性很差(换数据库就用不了), 用什么编写pl/sql ? sqlplus开发工具 sqlplus是oracle公司提供的一个工具,这个由于咱们在之前介绍过的: 举一个简单的案例: 编写一个存储过程,该过程能够向某表中添加记录。 1.建立一个简单的表
create table mytest(name varchar2(30),passwd varchar2(30));
2.建立过程
create or replace procedure sp_pro1 is
Oracle 笔记
37
begin--执行部分
insert into mytest values('韩顺平','m1234');
end;
/ replace:表示若是有sp_pro1,就替换 如何查看错误信息:show error; 如何调用该过程: 1)exec 过程名(参数值1,参数值2...); 2)call 过程名(参数值1,参数值2...); ? pl/sql developer开发工具 pl/sql developer是用于开发pl/sql块的集成开发环境(ide),它是一个独立的产品,而不是oracle的一个附带品。 举一个简单案例: 编写一个存储过程,该过程能够删除某表记录。
create or replace procedure sp_pro2 is
begin--执行部分
delete from mytest where name='韩顺平';
end; pl/sql基础 pl/sql介绍 ? 介绍 开发人员使用pl/sql编写应用模块时,不只须要掌握sql语句的编写方法,还要掌握pl/sql语句及语法规则。pl/sql编程能够使用变量和逻辑控制语句,从而能够编写很是有用的功能模块。好比:分页存储过程模块、订单处理存储过程模块、转帐存储过程模块。并且若是使用pl/sql编程,咱们能够轻松地完成很是复杂的查询要求。 pl/sql能够作什么 ? 简单分类 |————过程(存储过程) | |————函数 块(编程)—————| |————触发器 | |————包 编写规范 ? 编写规范 1.注释 单行注释 --
select * from emp where empno=7788; --取得员工信息 多行注释 /*...*/来划分 2.标志符号的命名规范 1).当定义变量时,建议用v_做为前缀v_sal 2).当定义常量时,建议用c_做为前缀c_rate 3).当定义游标时,建议用_cursor做为后缀emp_cursor 4).当定义例外时,建议用e_做为前缀e_error pl/sql块介绍 ? 介绍
Oracle 笔记
38
块(block)是pl/sql的基本程序单元,编写pl/sql程序实际上就是编写pl/sql块,要完成相对简单的应用功能,可能只须要编写一个pl/sql块,可是若是想要实现复杂的功能,可能须要在一个pl/sql块中嵌套其它的pl/sql块。 ? 块结构示意图 pl/sql块由三个部分构成:定义部分,执行部分,例外处理部分。 以下所示: declare /*定义部分——定义常量、变量、游标、例外、复杂数据类型*/ begin /*执行部分——要执行的pl/sql语句和sql语句*/ exception /*例外处理部分——处理运行的各类错误*/ end; 定义部分是从declare开始的,该部分是可选的; 执行部分是从begin开始的,该部分是必须的; 例外处理部分是从exception开始的,该部分是可选的。 能够和java编程结构作一个简单的比较。 pl/sql块的实例(1) ? 实例1-只包括执行部分的pl/sql块
set serveroutput on --打开输出选项
begin
dbms_output.put_line('hello');
end;
相关说明: dbms_output是oracle所提供的包(相似java的开发包),该包包含一些过程,put_line就是dbms_output包的一个过程。 pl/sql块的实例(2) ? 实例2-包含定义部分和执行部分的pl/sql块
declare
v_ename varchar2(5); --定义字符串变量
begin
select ename into v_ename from emp where empno=&aa;
dbms_output.put_line('雇员名:'||v_ename);
end;
/ 若是要把薪水也显示出来,那么执行部分就应该这么写:
select ename,sal into v_ename,v_sal from emp where empno=&aa;
相关说明: & 表示要接收从控制台输入的变量。 pl/sql块的实例(3) ? 实例3-包含定义部分,执行部分和例外处理部分 为了不pl/sql程序的运行错误,提升pl/sql的健壮性,应该对可能的错误进行处理,这个颇有必要。 1.好比在实例2中,若是输入了不存在的雇员号,应当作例外处理。 2.有时出现异常,但愿用另外的逻辑处理,[网示] 咱们看看如何完成1的要求。 相关说明: oracle事先预约义了一些例外,no_data_found就是找不到数据的例外。
Oracle 笔记
39
declare
--定义变量
v_ename varchar2(5);
v_sal number(7,2);
begin
--执行部分
select ename,sal into v_ename,v_sal from emp where empno=&aa;
--在控制台显示用户名
dbms_output.put_line('用户名是:'||v_ename||' 工资:'||v_sal);
--异常处理
exception
when no_data_found then
dbms_output.put_line('朋友,你的编号输入有误!');
end;
/
17.pl/sql分类 -- 过程,函数,包,触发器
? 过程 过程用于执行特定的操做,当创建过程时,既能够指定输入参数(in),也能够指定输出参数(out), 经过在过程当中使用输入参数,能够将数据传递到执行部分;经过使用输出参数,能够将执行部分的数据传递到应用环境。在sqlplus中能够使用create procedure命令来创建过程。 实例以下: 1.请考虑编写一个过程,能够输入雇员名,新工资,可修改雇员的工资 2.如何调用过程有两种方法; exec call 3.如何在java程序中调用一个存储过程 问题:如何使用过程返回值? 特别说明: 对于过程咱们会在之后给你们详细具体的介绍,如今请你们先有一个概念。 create procedure sp_pro3(spName varchar2, newSal number) is --不要写成number(3,2),代表类型就能够了,不须要大小。就好像Java写方法时的参数同样
begin
--执行部分,根据用户名去修改工资
update emp set sal=newSal where ename=spName;
end;
/ java程序中调用一个存储过程 //演示java程序去调用oracle的存储过程案例
import java.sql.*;
public class TestOraclePro{
public static void main(String[] args){
try{
//1.加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//2.获得链接
Oracle 笔记
40
Connection ct = DriverManager.getConnection("jdbc:oracle:thin@127.0.0.1:1521:MYORA1","scott","m123");
//3.建立CallableStatement
CallableStatement cs = ct.prepareCall("{call sp_pro3(?,?)}");
//4.给?赋值
cs.setString(1,"SMITH");
cs.setInt(2,10);
//5.执行
cs.execute();
//关闭
cs.close();
ct.close();
} catch(Exception e){
e.printStackTrace();
}
}
} ? 函数 函数用于返回特定的数据,当创建函数时,在函数头部必须包含return子句。而在函数体内必须包含return语句返回的数据。咱们能够使用create function来创建函数,实际案例:
--输入雇员的姓名,返回该雇员的年薪
create function annual_incomec(name varchar2)
return number is
annual_salazy number(7,2);
begin
--执行部分
select sal*12+nvl(comm, 0) into annual_salazy from emp where ename=name;
return annual_salazy;
end;
/
若是函数建立过程有编译错误,能够使用show error;命令显示错误 在sqlplus中调用函数
SQL> var income number
SQL> call annual_incomec('scott') into: income;
SQL> print income 一样咱们能够在java程序中调用该函数 select annual_income('SCOTT') from dual; 这样能够经过rs.getInt(l)获得返回的结果。 ? 包 包用于在逻辑上组合过程和函数,它由包规范和包体两部分组成。 1.咱们能够使用create package命令来建立包。 实例: --建立一个包sp_package --声明该包有一个过程update_sal --声明该包有一个函数annual_income
Oracle 笔记
41
create package sp_package is
procedure update_sal(name varchar2, newsal number);
function annual_income(name varchar2) return number;
end; 包的规范只包含了过程和函数的说明,可是没有过程和函数的实现代码。包体用于实现包规范中的过程和函数。 2.创建包体能够使用create package body命令 --给包sp_package实现包体
create or replace package body sp_package is
procedure update_sal(name varchar2, newsal number)
is
begin
update emp set sal = newsal where ename = name;
end;
function annual_income(name varchar2) return number is
annual_salary number;
begin
select sal * 12 + nvl(comm, 0) into annual_salary from emp
where ename = name;
return annual_salary;
end;
end;
/ 3.如何调用包的过程或是函数 当调用包的过程或是函数时,在过程和函数前须要带有包名,若是要访问其它方案的包,还须要在包名前加方案名。 如: SQL> call sp_package.update_sal('SCOTT', 1500); 特别说明: 包是pl/sql中很是重要的部分,咱们在使用过程分页时,将会再次体验它的威力呵呵。 ? 触发器 触发器是指隐含的执行的存储过程。当定义触发器时,必需要指定触发的事件和触发的操做,经常使用的触发事件包括insert,update,delete语句,而触发操做实际就是一个pl/sql块。能够使用create trigger来创建触发器。 特别说明: 咱们会在后面详细为你们介绍触发器的使用,由于触发器是很是有用的,可维护数据库的安全和一致性。
18.定义并使用变量,复合类型 定义并使用变量 ? 介绍 在编写pl/sql程序时,能够定义变量和常量;在pl/sql程序中包括有: 1.标量类型(scalar) 2.复合类型(composite) 3.参照类型(reference) 4.lob(large object) ? 标量(scalar)——经常使用类型 在编写pl/sql块时,若是要使用变量,需在定义部分定义变量。pl/sql中定义变量和常量的语法以下: identifier [constant] datatype [not null] [:=| default expr]
Oracle 笔记
42
identifier : 名称 constant :指定常量。须要指定它的初始值,且其值是不能改变的 datatype :数据类型 not null :指定变量值不能为null := 给变量或是常量指定初始值 default 用于指定初始值 expr :指定初始值的pl/sql表达式,能够是文本值、其它变量、函数等。 ? 标量定义的案例 1.定义一个变长字符串 v_ename varchar2(10); 2.定义一个小数,范围 -9999.99~9999.99 v_sal number(6,2); 3.定义一个小数并给一个初始值为5.4 :=是pl/sql的赋值号 v_sal2 number(6,2):=5.4; 4.定义一个日期类型的数据 v_hiredate date; 5.定义一个布尔变量,不能为空,初始值为false v_valid boolean not null default false; ? 标量(scalar)——使用标量 在定义好变量后,就能够使用这些变量。这里须要说明的是pl/sql块为变量赋值不一样于其它的编程语言,须要在等号前面加冒号(:=) 下面以输入员工号,显示雇员姓名、工资、我的所得税(税率为0.03)为例。说明变量的使用,看看如何编写。
declare
c_tax_rate number(3,2):=0.03;
--用户名
v_ename varchar2(5);
v_sal number(7,2);
v_tax_sal number(7,2);
begin
--执行
select ename,sal into v_ename,v_sal from emp where empno=&no;
--计算所得税
v_tax_sal := v_sal*c_tax_rate;
--输出
dbms_output.put_line('姓名是:'||v_ename||'工资:'||v_sal||' 交税:'||v_tax_sal);
end;
/ ? 标量(scalar)——使用%type类型 对于上面的pl/sql块有一个问题: 就是若是员工的姓名超过了5个字符的话,就会有错误,为了下降pl/sql程序的维护工做量,能够使用%type属性定义变量,这样它会按照数据库列来肯定你定义的变量的类型和长度。 咱们看看这个怎么使用: 标识符名 表名.列名%type; 好比上例的v_ename,这样定义: v_ename emp.ename%type;
Oracle 笔记
43
? 复合变量(composite)——介绍 用于存放多个值的变量。主要包括这几种: 1.pl/sql记录 2.pl/sql表 3.嵌套表 4.varray ? 复合类型——pl/sql记录 相似于高级语言中的结构体,须要注意的是,当引用pl/sql记录成员时,必需要加记录变量做为前缀(记录变量.记录成员)以下:
declare
--定义一个pl/sql记录类型emp_record_type,类型包含3个数据name,salary,title。说白了,就是一个类型能够存放3个数据,主要是为了好管理
type emp_record_type is record(
name emp.ename%type,
salary emp.sal%type,
title emp.job%type);
--定义了一个sp_record变量,这个变量的类型是emp_record_type
sp_record emp_record_type;
begin
select ename, sal, job into sp_record from emp where empno = 7788;
dbms_output.put_line ('员工名:' || sp_record.name);
end; ? 复合类型-pl/sql表 至关于高级语言中的数组,可是须要注意的是在高级语言中数组的下标不能为负数,而pl/sql是能够为负数的,而且表元素的下标没有限制。实例以下:
declare
--定义了一个pl/sql表类型sp_table_type,该类型是用于存放emp.ename%type
--index by binary_integer 表示下标是整数
type sp_table_type is table of emp.ename%type
index by binary_integer;
--定义了一个sp_table变量,这个变量的类型是sp_table_type
sp_table sp_table_type;
begin
select ename into sp_table(-1) from emp where empno = 7788;
dbms_output.put_line('员工名:' || sp_table(-1));
end;
说明: sp_table_type 是pl/sql表类型 emp.ename%type 指定了表的元素的类型和长度 sp_table 为pl/sql表变量 sp_table(0) 则表示下标为0的元素 注意:若是把select ename into sp_table(-1) from emp where empno = 7788;变成select ename into sp_table(-1) from emp;则运行时会出现错误,错误以下: ORA-01422:实际返回的行数超出请求的行数 解决方法是:使用参照变量(这里不讲)
Oracle 笔记
44
? 复合变量——嵌套表(nested table) ? 复合变量——变长数组(varray) ? 参照变量——介绍 参照变量是指用于存放数值指针的变量。经过使用参照变量,能够使得应用程序共享相同对象,从而下降占用的空间。在编写pl/sql程序时,能够使用游标变量(ref cursor)和对象类型变量(ref obj_type)两种参照变量类型。 ? 参照变量——ref cursor游标变量 使用游标时,当定义游标时不须要指定相应的select语句,可是当使用游标时(open时)须要指定select语句,这样一个游标就与一个select语句结合了。实例以下: 1.请使用pl/sql编写一个块,能够输入部门号,并显示该部门全部员工姓名和他的工资。 2.在1的基础上,若是某个员工的工资低于200元,就添加100元。 1.
declare
--定义游标sp_emp_cursor
type sp_emp_cursor is ref cursor;
--定义一个游标变量
test_cursor sp_emp_cursor;
--定义变量
v_ename emp.ename%type;
v_sal emp.sal%type;
begin
--执行
--把test_cursor和一个select结合
open test_cursor for select ename,sal from emp where deptno=&no;
--循环取出
loop
fetch test_cursor into v_ename,v_sal;
--判断是否test_cursor为空
exit when test_cursor%notfound;
dbms_output.put_line('名字:'||v_ename||' 工资:'||v_sal);
end loop;
end;
/
19.pl/sql的进阶--控制结构(分支,循环,控制)
玩转oracle实战教程(第七天) 内容介绍 1.上节回顾 2.pl/sql的进阶 √ 3.oracle的视图(具备安全性,和简化复杂查询的功能) √ 4.oracle的触发器 √ 指望目标 1.掌握pl/sql的高级用法(能缩写分页过程模块,下订单过程模块...) 2.会处理oracle常见的例外 3.会编写oracle各类触发器
Oracle 笔记
45
4.理解视图的概念并能灵活使用视图 pl/sql的进阶--控制结构 ? 介绍 在任何计算机语言(c,java,pascal)都有各类控制语句(条件语句,循环结构,顺序控制结构...)在pl/sql中也存在这样的控制结构。 在本部分学习完成后,但愿你们达到: 1.使用各类if语句 2.使用循环语句 3.使用控制语句——goto和null; ? 条件分支语句 pl/sql中提供了三种条件分支语句if—then,if – then – else,if – then – elsif – then 这里咱们能够和java语句进行一个比较 ? 简单的条件判断 if – then 问题:编写一个过程,能够输入一个雇员名,若是该雇员的工资低于2000,就给该员工工资增长10%。
create or replace procedure sp_pro6(spName varchar2) is
--定义
v_sal emp.sal%type;
begin
--执行
select sal into v_sal from emp where ename=spName;
--判断
if v_sal<2000 then
update emp set sal=sal+sal*10% where ename=spName;
end if;
end;
/ ? 二重条件分支 if – then – else 问题:编写一个过程,能够输入一个雇员名,若是该雇员的补助不是0就在原来的基础上增长100;若是补助为0就把补助设为200;
create or replace procedure sp_pro6(spName varchar2) is
--定义
v_comm emp.comm%type;
begin
--执行
select comm into v_comm from emp where ename=spName;
--判断
if v_comm<>0 then
update emp set comm=comm+100 where ename=spName;
else
update emp set comm=comm+200 where ename=spName;
end if;
end;
/ ? 多重条件分支 if – then – elsif – then
Oracle 笔记
46
问题:编写一个过程,能够输入一个雇员编号,若是该雇员的职位是PRESIDENT就给他的工资增长1000,若是该雇员的职位是MANAGER就给他的工资增长500,其它职位的雇员工资增长200。
create or replace procedure sp_pro6(spNo number) is
--定义
v_job emp.job%type;
begin
--执行
select job into v_job from emp where empno=spNo;
if v_job='PRESIDENT' then
update emp set sal=sal+1000 where empno=spNo;
elsif v_job='MANAGER' then
update emp set sal=sal+500 where empno=spNo;
else
update emp set sal=sal+200 where empno=spNo;
end if;
end;
/ ? 循环语句 –loop 是pl/sql中最简单的循环语句,这种循环语句以loop开头,以end loop结尾,这种循环至少会被执行一次。 案例:现有一张表users,表结构以下: 用户id | 用户名 | 请编写一个过程,能够输入用户名,并循环添加10个用户到users表中,用户编号从1开始增长。
create or replace procedure sp_pro6(spName varchar2) is
--定义 :=表示赋值
v_num number:=1;
begin
loop
insert into users values(v_num,spName);
--判断是否要退出循环
exit when v_num=10;
--自增
v_num:=v_num+1;
end loop;
end;
/ ? 环语句 –while循环 基本循环至少要执行循环体一次,而对于while循环来讲,只有条件为true时,才会执行循环体语句,while循环以while...loop开始,以end loop结束。 案例:现有一张表users,表结构以下: 用户id 用户名 问题:请编写一个过程,能够输入用户名,并循环添加10个用户到users表中,用户编号从11开始增长。
create or replace procedure sp_pro6(spName varchar2) is
--定义 :=表示赋值
v_num number:=11;
Oracle 笔记
47
begin
while v_num<=20 loop
--执行
insert into users values(v_num,spName);
v_num:=v_num+1;
end loop;
end;
/ ? 循环语句 –for循环 基本for循环的基本结构以下
begin
for i in reverse 1..10 loop
insert into users values (i, 'shunping');
end loop;
end;
咱们能够看到控制变量i,在隐含中就在不停地增长。 ? 顺序控制语句 –goto,null 1.goto语句 goto语句用于跳转到特定符号去执行语句。注意因为使用goto语句会增长程序的复杂性,并使得应用程序可读性变差,因此在作通常应用开发时,建议你们不要使用goto语句。 基本语法以下 goto lable,其中lable是已经定义好的标号名,
declare
i int := 1;
begin
loop
dbms_output.put_line('输出i=' || i);
if i = 1{} then
goto end_loop;
end if;
i := i + 1;
end loop;
<<end_loop>>
dbms_output.put_line('循环结束');
end; 2.null null语句不会执行任何操做,而且会直接将控制传递到下一条语句。使用null语句的主要好处是能够提升pl/sql的可读性。
declare
v_sal emp.sal%type;
v_ename emp.ename%type;
begin
select ename, sal into v_ename, v_sal from emp where empno = &no;
if v_sal < 3000 then
update emp set comm = sal * 0.1 where ename = v_ename;
else
null;
Oracle 笔记
48
end if;
end;
20.PL/SQL分页 编写分页过程 ? 介绍 分页是任何一个网站(bbs,网上商城,blog)都会使用到的技术,所以学习pl/sql编程开发就必定要掌握该技术。看图: ? 无返回值的存储过程 古人云:欲速则不达,为了让你们伙比较容易接受分页过程编写,我仍是从简单到复杂,按部就班的给你们讲解。首先是掌握最简单的存储过程,无返回值的存储过程: 案例:现有一张表book,表结构以下:看图: 书号 书名 出版社 请写一个过程,能够向book表添加书,要求经过java程序调用该过程。 --in:表示这是一个输入参数,默认为in --out:表示一个输出参数
create or replace procedure sp_pro7(spBookId in number,spbookName in varchar2,sppublishHouse in varchar2) is
begin
insert into book values(spBookId,spbookName,sppublishHouse);
end;
/ --在java中调用
//调用一个无返回值的过程
import java.sql.*;
public class Test2{
public static void main(String[] args){
try{
//1.加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//2.获得链接
Connection ct = DriverManager.getConnection("jdbc:oracle:thin@127.0.0.1:1521:MYORA1","scott","m123");
//3.建立CallableStatement
CallableStatement cs = ct.prepareCall("{call sp_pro7(?,?,?)}");
//4.给?赋值
cs.setInt(1,10);
cs.setString(2,"笑傲江湖");
cs.setString(3,"人民出版社");
//5.执行
cs.execute();
} catch(Exception e){
e.printStackTrace();
} finally{
//6.关闭各个打开的资源
cs.close
//Oracle 笔记
ct.close();
}
}
}
执行,记录被加进去了 ? 有返回值的存储过程(非列表) 再看如何处理有返回值的存储过程: 案例:编写一个过程,能够输入雇员的编号,返回该雇员的姓名。 案例扩张:编写一个过程,能够输入雇员的编号,返回该雇员的姓名、工资和岗位。
--有输入和输出的存储过程
create or replace procedure sp_pro8
(spno in number, spName out varchar2) is
begin
select ename into spName from emp where empno=spno;
end;
/
import java.sql.*;
public class Test2{
public static void main(String[] args){
try{
//1.加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//2.获得链接
Connection ct = DriverManager.getConnection("jdbc:oracle:thin@127.0.0.1:1521:MYORA1","scott","m123");
//3.建立CallableStatement
/*CallableStatement cs = ct.prepareCall("{call sp_pro7(?,?,?)}");
//4.给?赋值
cs.setInt(1,10);
cs.setString(2,"笑傲江湖");
cs.setString(3,"人民出版社");*/
//看看如何调用有返回值的过程
//建立CallableStatement
/*CallableStatement cs = ct.prepareCall("{call sp_pro8(?,?)}");
//给第一个?赋值
cs.setInt(1,7788);
//给第二个?赋值
cs.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);
//5.执行
cs.execute();
//取出返回值,要注意?的顺序
String name=cs.getString(2);
System.out.println("7788的名字"+name);
} catch(Exception e){
e.printStackTrace();
Oracle 笔记
50
} finally{
//6.关闭各个打开的资源
cs.close();
ct.close();
}
}
}
运行,成功得出结果。。 案例扩张:编写一个过程,能够输入雇员的编号,返回该雇员的姓名、工资和岗位。
--有输入和输出的存储过程
create or replace procedure sp_pro8
(spno in number, spName out varchar2,spSal out number,spJob out varchar2) is
begin
select ename,sal,job into spName,spSal,spJob from emp where empno=spno;
end;
/
import java.sql.*;
public class Test2{
public static void main(String[] args){
try{
//1.加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//2.获得链接
Connection ct = DriverManager.getConnection("jdbc:oracle:thin@127.0.0.1:1521:MYORA1","scott","m123");
//3.建立CallableStatement
/*CallableStatement cs = ct.prepareCall("{call sp_pro7(?,?,?)}");
//4.给?赋值
cs.setInt(1,10);
cs.setString(2,"笑傲江湖");
cs.setString(3,"人民出版社");*/
//看看如何调用有返回值的过程
//建立CallableStatement
/*CallableStatement cs = ct.prepareCall("{call sp_pro8(?,?,?,?)}");
//给第一个?赋值
cs.setInt(1,7788);
//给第二个?赋值
cs.registerOutParameter(2,oracle.jdbc.OracleTypes.VARCHAR);
//给第三个?赋值
cs.registerOutParameter(3,oracle.jdbc.OracleTypes.DOUBLE);
//给第四个?赋值
cs.registerOutParameter(4,oracle.jdbc.OracleTypes.VARCHAR);
//5.执行
cs.execute();
//取出返回值,要注意?的顺序
Oracle 笔记
51
String name=cs.getString(2);
String job=cs.getString(4);
System.out.println("7788的名字"+name+" 工做:"+job);
} catch(Exception e){
e.printStackTrace();
} finally{
//6.关闭各个打开的资源
cs.close();
ct.close();
}
}
}
运行,成功找出记录 ? 有返回值的存储过程(列表[结果集]) 案例:编写一个过程,输入部门号,返回该部门全部雇员信息。 对该题分析以下: 因为oracle存储过程没有返回值,它的全部返回值都是经过out参数来替代的,列表一样也不例外,但因为是集合,因此不能用通常的参数,必需要用pagkage了。因此要分两部分: 返回结果集的过程 1.创建一个包,在该包中,我定义类型test_cursor,是个游标。 以下:
create or replace package testpackage as
TYPE test_cursor is ref cursor;
end testpackage; 2.创建存储过程。以下:
create or replace procedure sp_pro9(spNo in number,p_cursor out testpackage.test_cursor) is
begin
open p_cursor for
select * from emp where deptno = spNo;
end sp_pro9; 3.如何在java程序中调用该过程
import java.sql.*;
public class Test2{
public static void main(String[] args){
try{
//1.加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//2.获得链接
Connection ct = DriverManager.getConnection("jdbc:oracle:thin@127.0.0.1:1521:MYORA1","scott","m123");
//看看如何调用有返回值的过程
//3.建立CallableStatement
/*CallableStatement cs = ct.prepareCall("{call sp_pro9(?,?)}");
//4.给第?赋值
cs.setInt(1,10);
//给第二个?赋值
Oracle 笔记
52
cs.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR);
//5.执行
cs.execute();
//获得结果集
ResultSet rs=(ResultSet)cs.getObject(2);
while(rs.next()){
System.out.println(rs.getInt(1)+" "+rs.getString(2));
}
} catch(Exception e){
e.printStackTrace();
} finally{
//6.关闭各个打开的资源
cs.close();
ct.close();
}
}
}
运行,成功得出部门号是10的全部用户 ? 编写分页过程 有了上面的基础,相信你们能够完成分页存储过程了。 要求,请你们编写一个存储过程,要求能够输入表名、每页显示记录数、当前页。返回总记录数,总页数,和返回的结果集。 若是你们忘了oracle中如何分页,请参考第三天的内容。 先本身完成,老师在后面给出答案,并讲解。 --oracle的分页
select t1.*, rownum rn from (select * from emp) t1 where rownum<=10;
--在分页时,你们能够把下面的sql语句当作一个模板使用
select * from
(select t1.*, rownum rn from (select * from emp) t1 where rownum<=10)
where rn>=6; --开发一个包 --创建一个包,在该包中,我定义类型test_cursor,是个游标。 以下:
create or replace package testpackage as
TYPE test_cursor is ref cursor;
end testpackage;
--开始编写分页的过程
create or replace procedure fenye
(tableName in varchar2,
Pagesize in number,--一页显示记录数
pageNow in number,
myrows out number,--总记录数
myPageCount out number,--总页数
p_cursor out testpackage.test_cursor--返回的记录集
) is
--定义部分
--定义sql语句 字符串
Oracle 笔记
53
v_sql varchar2(1000);
--定义两个整数
v_begin number:=(pageNow-1)*Pagesize+1;
v_end number:=pageNow*Pagesize;
begin
--执行部分
v_sql:='select * from (select t1.*, rownum rn from (select * from '||tableName||') t1 where rownum<='||v_end||') where rn>='||v_begin;
--把游标和sql关联
open p_cursor for v_sql;
--计算myrows和myPageCount
--组织一个sql语句
v_sql:='select count(*) from '||tableName;
--执行sql,并把返回的值,赋给myrows;
execute inmediate v_sql into myrows;
--计算myPageCount
--if myrows%Pagesize=0 then这样写是错的
if mod(myrows,Pagesize)=0 then
myPageCount:=myrows/Pagesize;
else
myPageCount:=myrows/Pagesize+1
end if;
--关闭游标
close p_cursor;
end;
/ --使用java测试 //测试分页
import java.sql.*;
public class FenYe{
public static void main(String[] args){
try{
//1.加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//2.获得链接
Connection ct = DriverManager.getConnection("jdbc:oracle:thin@127.0.0.1:1521:MYORA1","scott","m123");
//3.建立CallableStatement
CallableStatement cs = ct.prepareCall("{call fenye(?,?,?,?,?,?)}");
//4.给第?赋值
cs.seString(1,"emp");
cs.setInt(2,5);
cs.setInt(3,2);
//注册总记录数
Oracle 笔记
54
cs.registerOutParameter(4,oracle.jdbc.OracleTypes.INTEGER);
//注册总页数
cs.registerOutParameter(5,oracle.jdbc.OracleTypes.INTEGER);
//注册返回的结果集
cs.registerOutParameter(6,oracle.jdbc.OracleTypes.CURSOR);
//5.执行
cs.execute();
//取出总记录数 /这里要注意,getInt(4)中4,是由该参数的位置决定的
int rowNum=cs.getInt(4);
int pageCount = cs.getInt(5);
ResultSet rs=(ResultSet)cs.getObject(6);
//显示一下,看看对不对
System.out.println("rowNum="+rowNum);
System.out.println("总页数="+pageCount);
while(rs.next()){
System.out.println("编号:"+rs.getInt(1)+" 名字:"+rs.getString(2)+" 工资:"+rs.getFloat(6));
}
} catch(Exception e){
e.printStackTrace();
} finally{
//6.关闭各个打开的资源
cs.close();
ct.close();
}
}
}
运行,控制台输出: rowNum=19 总页数:4 编号:7369 名字:SMITH 工资:2850.0 编号:7499 名字:ALLEN 工资:2450.0 编号:7521 名字:WARD 工资:1562.0 编号:7566 名字:JONES 工资:7200.0 编号:7654 名字:MARTIN 工资:1500.0 --新的须要,要求按照薪水从低到高排序,而后取出6-10 过程的执行部分作下改动,以下:
begin
--执行部分
v_sql:='select * from (select t1.*, rownum rn from (select * from '||tableName||' order by sal) t1 where rownum<='||v_end||') where rn>='||v_begin; 从新执行一次procedure,java不用改变,运行,控制台输出: rowNum=19 总页数:4 编号:7900 名字:JAMES 工资:950.0 编号:7876 名字:ADAMS 工资:1100.0
Oracle 笔记
55
编号:7521 名字:WARD 工资:1250.0 编号:7654 名字:MARTIN 工资:1250.0 编号:7934 名字:MILLER 工资:1300.0
21.例外处理 例外处理 ? 例外的分类 oracle将例外分为预约义例外,非预约义例外和自定义例外三种。 预约义例外用于处理常见的oracle错误 非预约义例外用于处理预约义例外不能处理的例外 自定义例外用于处理与oracle错误无关的其它状况 ? 例外传递 若是不处理例外咱们看看会出现什么状况: 案例,编写一个过程,可接收雇员的编号,并显示该雇员的姓名。 问题是,若是输入的雇员编号不存在,怎样去处理呢?
--例外案例
declare
--定义
v_ename emp.ename%type;
begin
--
select ename into v_ename from emp where empno=&gno;
dbms_output.put_line('名字:'||v_ename)
/ 执行,弹出框,看图: 随便输个不在的编号,回车,会抛出异常,显示: ORA-01403: 未找到数据 ORA-06512: 在line 6
declare
--定义
v_ename emp.ename%type;
begin
--
select ename into v_ename from emp where empno=&gno;
dbms_output.put_line('名字:'||v_ename)
exception
when no_data_found then
dbms_output.put_line('编号没有!');
/
执行,输入一个不存在的编号,回车,显示: 编号没有! ? 处理预约义例外 预约义例外是由pl/sql所提供的系统例外。当pl/sql应用程序违反了oracle 规定的限制时,则会隐含的触发一个内部例外。pl/sql为开发人员提供了二十多个预约义例外。咱们给你们介绍经常使用的例外。
Oracle 笔记
56
? 预约义例外 case_not_found 在开发pl/sql块中编写case语句时,若是在when子句中没有包含必须的条件分支,就会触发case_not_found的例外:
create or replace procedure sp_pro6(spno number) is
v_sal emp.sal%type;
begin
select sal into v_sal from emp where empno = spno;
case
when v_sal < 1000 then
update emp set sal = sal + 100 where empno = spno;
when v_sal < 2000 then
update emp set sal = sal + 200 where empno = spno;
end case;
exception
when case_not_found then
dbms_output.put_line('case语句没有与' || v_sal || '相匹配的条件');
end; ? 预约义例外 cursor_already_open 当从新打开已经打开的游标时,会隐含的触发例外cursor_already_open
declare
cursor emp_cursor is select ename, sal from emp;
begin
open emp_cursor;
for emp_record1 in emp_cursor loop
dbms_output.put_line(emp_record1.ename);
end loop;
exception
when cursor_already_open then
dbms_output.put_line('游标已经打开');
end;
/ ? 预约义例外 dup_val_on_index 在惟一索引所对应的列上插入重复的值时,会隐含的触发例外dup_val_on_index例外
begin
insert into dept values (10, '公关部', '北京');
exception
when dup_val_on_index then
dbms_output.put_line('在deptno列上不能出现重复值');
end; ? 预约义例外 invalid_cursor 当试图在不合法的游标上执行操做时,会触发该例外 例如:试图从没有打开的游标提取数据,或是关闭没有打开的游标。则会触发该例外
declare
cursor emp_cursor is select ename, sal from emp;
emp_record emp_cursor%rowtype;
begin
Oracle 笔记
57
--open emp_cursor; --打开游标
fetch emp_cursor into emp_record;
dbms_output.put_line(emp_record.ename);
close emp_cursor;
exception
when invalid_cursor then
dbms_output.put_line('请检测游标是否打开');
end; ? 预约义例外 invalid_number 当输入的数据有误时,会触发该例外 好比:数字100写成了loo就会触发该例外
begin
update emp set sal= sal + 'loo';
exception
when invalid_number then
dbms_output.put_line('输入的数字不正确');
end; 预约义例外 no_data_found 下面是一个pl/sql块,当执行select into 没有返回行,就会触发该例外
declare
v_sal emp.sal%type;
begin
select sal into v_sal from emp
when ename='&name';
exception
when no_data_found then
dbms_output.put_line('不存在该员工');
end; ? 预约义例外 too_many_rows 当执行select into语句时,若是返回超过了一行,则会触发该例外。
declare
v_ename emp.ename%type;
begin
select ename into v_ename from emp;
exception
when too_many_rows then
dbms_output.put_line('返回了多行');
end; ? 预义例外 zero_divide 当执行2/0语句时,则会触发该例外。 ? 预约义例外 value_error 当在执行赋值操做时,若是变量的长度不足以容纳实际数据,则会触发该例外value_error,好比:
declare
v_ename varchar2(5);
begin
Oracle 笔记
58
select ename into v_ename from emp where empno = &no1;
dbms_output.put_line(v_ename);
exception
when value_error then
dbms_output.put_line('变量尺寸不足');
end; ? 其它预约义例外(这些例外不是在pl/sql里触发的,而是在用oracle时触发的,因此取名叫其它预约义例外) 1.login_denied 当用户非法登陆时,会触发该例外 2.not_logged_on 若是用户没有登陆就执行dml操做,就会触发该例外 3.storage_error 若是超过了内存空间或是内存被损坏,就触发该例外 4.timeout_on_resource 若是oracle在等待资源时,出现了超时就触发该例外 ? 非预约义例外 非预约义例外用于处理与预约义例外无关的oracle错误。使用预约义例外只能处理21个oracle错误,而当使用pl/sql开发应用程序时,可能会遇到其它的一些oracle错误。好比在pl/sql块中执行dml语句时,违反了约束规定等等。在这样的状况下,也能够处理oracle的各类例外,由于非预约义例外用的很少,这里我就不举例了。 ? 处理自定义例外 预约义例外和自定义例外都是与oracle错误相关的,而且出现的oracle错误会隐含的触发相应的例外;而自定义例外与oracle错误没有任何关联,它是由开发人员为特定状况所定义的例外. 问题:请编写一个pl/sql块,接收一个雇员的编号,并给该雇员工资增长1000元,若是该雇员不存在,请提示。
--自定义例外
create or replace procedure ex_test(spNo number)
is
begin
--更新用户sal
update emp set sal=sal+1000 where empno=spNo;
end;
/ 运行,该过程被成功建立。 SQL> exec ex_test(56); PL/SQL过程被成功完成 这里,编号为56是不存在的,刚才的报异常了,为何如今不报异常呢? 由于刚才的是select语句 怎么解决这个问题呢? 修改代码,以下:
--自定义例外
create or replace procedure ex_test(spNo number)
is
--定义一个例外
myex exception;
begin
--更新用户sal
update emp set sal=sal+1000 where empno=spNo;
Oracle 笔记
59
--sql%notfound这是表示没有update
--raise myex;触发myex
if sql%notfound then
raise myex;
end if;
exception
when myex then
dbms_output.put_line('没有更新任何用户');
end;
/ 如今再测试一次: SQL> exec ex_test(56); 没有更新任何用户
22.oracle的视图 oracle的视图 ? 介绍 视图是一个虚拟表,其内容由查询定义,同真实的表同样,视图包含一系列带有名称的列和行数据。可是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,而且在引用视图时动态生成。(视图不是真实存在磁盘上的) 看图: 视与表的区别 ? 视图与表的区别 1.表须要占用磁盘空间,视图不须要 2.视图不能添加索引(因此查询速度略微慢点) 3.使用视图能够简化,复杂查询 好比:学生选课系统 4.视图的使用利于提升安全性 好比:不一样用户查看不一样视图 建立/修改视图 ? 建立视图 create view 视图名 as select 语句 [with read only] ? 建立或修改视图 create or replace view 视图名 as select 语句 [with read only] ? 删除视图 drop view 视图名 当表结构国语复杂,请使用视图吧! --建立视图,把emp表的sal<1000的雇员映射到该视图(view)
create view myview as select * from emp where sal<1000; --为简化操做,用一个视图解决 显示雇员编号,姓名和部门名称
create view myview2 as select emp.empno,emp.ename,dept.dname from emp,dept where emp.deptno=dept.deptno; 视图之间也能够作联合查询</pre>
<p> </p>
<pre name="code" >1、基础
一、说明:建立数据库
CREATE DATABASE database-name
二、说明:删除数据库
drop database dbname
三、说明:备份sql server
--- 建立 备份数据的 device
USE master
EXEC sp_addumpdevice 'disk', 'testBack', 'c:\mssql7backup\MyNwind_1.dat'
--- 开始 备份
BACKUP DATABASE pubs TO testBack
四、说明:建立新表
create table tabname(col1 type1 [not null] [primary key],col2 type2 [not null],..)
根据已有的表建立新表:
A:create table tab_new like tab_old (使用旧表建立新表)
B:create table tab_new as select col1,col2… from tab_old definition only
五、说明:删除新表
drop table tabname
六、说明:增长一个列
Alter table tabname add column col type
注:列增长后将不能删除。DB2中列加上后数据类型也不能改变,惟一能改变的是增长varchar类型的长度。
七、说明:添加主键: Alter table tabname add primary key(col)
说明:删除主键: Alter table tabname drop primary key(col)
八、说明:建立索引:create [unique] index idxname on tabname(col….)
删除索引:drop index idxname
注:索引是不可更改的,想更改必须删除从新建。
九、说明:建立视图:create view viewname as select statement
删除视图:drop view viewname
十、说明:几个简单的基本的sql语句
选择:select * from table1 where 范围
插入:insert into table1(field1,field2) values(value1,value2)
删除:delete from table1 where 范围
更新:update table1 set field1=value1 where 范围
查找:select * from table1 where field1 like ’%value1%’ ---like的语法很精妙,查资料!
排序:select * from table1 order by field1,field2 [desc]
总数:select count as totalcount from table1
求和:select sum(field1) as sumvalue from table1
平均:select avg(field1) as avgvalue from table1
最大:select max(field1) as maxvalue from table1
最小:select min(field1) as minvalue from table1
十一、说明:几个高级查询运算词
A: UNION 运算符
UNION 运算符经过组合其余两个结果表(例如 TABLE1 和 TABLE2)并消去表中任何重复行而派生出一个结果表。当 ALL 随 UNION 一块儿使用时(即 UNION ALL),不消除重复行。两种状况下,派生表的每一行不是来自 TABLE1 就是来自 TABLE2。
B: EXCEPT 运算符
EXCEPT 运算符经过包括全部在 TABLE1 中但不在 TABLE2 中的行并消除全部重复行而派生出一个结果表。当 ALL 随 EXCEPT 一块儿使用时 (EXCEPT ALL),不消除重复行。
C: INTERSECT 运算符
INTERSECT 运算符经过只包括 TABLE1 和 TABLE2 中都有的行并消除全部重复行而派生出一个结果表。当 ALL 随 INTERSECT 一块儿使用时 (INTERSECT ALL),不消除重复行。
注:使用运算词的几个查询结果行必须是一致的。
十二、说明:使用外链接
A、left (outer) join:
左外链接(左链接):结果集几包括链接表的匹配行,也包括左链接表的全部行。
SQL: select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
B:right (outer) join:
右外链接(右链接):结果集既包括链接表的匹配链接行,也包括右链接表的全部行。
C:full/cross (outer) join:
全外链接:不只包括符号链接表的匹配行,还包括两个链接表中的全部记录。
十二、分组:Group by:
一张表,一旦分组 完成后,查询后只能获得组相关的信息。
组相关的信息:(统计信息) count,sum,max,min,avg 分组的标准)
在SQLServer中分组时:不能以text,ntext,image类型的字段做为分组依据
在selecte统计函数中的字段,不能和普通的字段放在一块儿;
1三、对数据库进行操做:
分离数据库: sp_detach_db; 附加数据库:sp_attach_db 后接代表,附加须要完整的路径名
14.如何修改数据库的名称:
sp_renamedb 'old_name', 'new_name'
2、提高
一、说明:复制表(只复制结构,源表名:a 新表名:b) (Access可用)
法一:select * into b from a where 1<>1(仅用于SQlServer)
法二:select top 0 * into b from a
二、说明:拷贝表(拷贝数据,源表名:a 目标表名:b) (Access可用)
insert into b(a, b, c) select d,e,f from b;
三、说明:跨数据库之间表的拷贝(具体数据使用绝对路径) (Access可用)
insert into b(a, b, c) select d,e,f from b in ‘具体数据库’ where 条件
例子:..from b in '"&Server.MapPath(".")&"\data.mdb" &"' where..
四、说明:子查询(表名1:a 表名2:b)
select a,b,c from a where a IN (select d from b ) 或者: select a,b,c from a where a IN (1,2,3)
五、说明:显示文章、提交人和最后回复时间
select a.title,a.username,b.adddate from table a,(select max(adddate) adddate from table where table.title=a.title) b
六、说明:外链接查询(表名1:a 表名2:b)
select a.a, a.b, a.c, b.c, b.d, b.f from a LEFT OUT JOIN b ON a.a = b.c
七、说明:在线视图查询(表名1:a )
select * from (SELECT a,b,c FROM a) T where t.a > 1;
八、说明:between的用法,between限制查询数据范围时包括了边界值,not between不包括
select * from table1 where time between time1 and time2
select a,b,c, from table1 where a not between 数值1 and 数值2
九、说明:in 的使用方法
select * from table1 where a [not] in (‘值1’,’值2’,’值4’,’值6’)
十、说明:两张关联表,删除主表中已经在副表中没有的信息
delete from table1 where not exists ( select * from table2 where table1.field1=table2.field1 )
十一、说明:四表联查问题:
select * from a left inner join b on a.a=b.b right inner join c on a.a=c.c inner join d on a.a=d.d where .....
十二、说明:日程安排提早五分钟提醒
SQL: select * from 日程安排 where datediff('minute',f开始时间,getdate())>5
1三、说明:一条sql 语句搞定数据库分页
select top 10 b.* from (select top 20 主键字段,排序字段 from 表名 order by 排序字段 desc) a,表名 b where b.主键字段 = a.主键字段 order by a.排序字段
具体实现:
关于数据库分页:
declare @start int,@end int
@sql nvarchar(600)
set @sql=’select top’+str(@end-@start+1)+’+from T where rid not in(select top’+str(@str-1)+’Rid from T where Rid>-1)’
exec sp_executesql @sql
注意:在top后不能直接跟一个变量,因此在实际应用中只有这样的进行特殊的处理。Rid为一个标识列,若是top后还有具体的字段,这样作是很是有好处的。由于这样能够避免 top的字段若是是逻辑索引的,查询的结果后实际表中的不一致(逻辑索引中的数据有可能和数据表中的不一致,而查询时若是处在索引则首先查询索引)
1四、说明:前10条记录
select top 10 * form table1 where 范围
1五、说明:选择在每一组b值相同的数据中对应的a最大的记录的全部信息(相似这样的用法能够用于论坛每个月排行榜,每个月热销产品分析,按科目成绩排名,等等.)
select a,b,c from tablename ta where a=(select max(a) from tablename tb where tb.b=ta.b)
1六、说明:包括全部在 TableA 中但不在 TableB和TableC 中的行并消除全部重复行而派生出一个结果表
(select a from tableA ) except (select a from tableB) except (select a from tableC)
1七、说明:随机取出10条数据
select top 10 * from tablename order by newid()
1八、说明:随机选择记录
select newid()
1九、说明:删除重复记录
1),delete from tablename where id not in (select max(id) from tablename group by col1,col2,...)
2),select distinct * into temp from tablename
delete from tablename
insert into tablename select * from temp
评价: 这种操做牵连大量的数据的移动,这种作法不适合大容量但数据操做
3),例如:在一个外部表中导入数据,因为某些缘由第一次只导入了一部分,但很难判断具体位置,这样只有在下一次所有导入,这样也就产生好多重复的字段,怎样删除重复字段
alter table tablename
--添加一个自增列
add column_b int identity(1,1)
delete from tablename where column_b not in(
select max(column_b) from tablename group by column1,column2,...)
alter table tablename drop column column_b
20、说明:列出数据库里全部的表名
select name from sysobjects where type='U' // U表明用户
2一、说明:列出表里的全部的列名
select name from syscolumns where id=object_id('TableName')
2二、说明:列示type、vender、pcs字段,以type字段排列,case能够方便地实现多重选择,相似select 中的case。
select type,sum(case vender when 'A' then pcs else 0 end),sum(case vender when 'C' then pcs else 0 end),sum(case vender when 'B' then pcs else 0 end) FROM tablename group by type
显示结果:
type vender pcs
电脑 A 1
电脑 A 1
光盘 B 2
光盘 A 2
手机 B 3
手机 C 3
2三、说明:初始化表table1
TRUNCATE TABLE table1
2四、说明:选择从10到15的记录
select top 5 * from (select top 15 * from table order by id asc) table_别名 order by id desc
3、技巧
一、1=1,1=2的使用,在SQL语句组合时用的较多
“where 1=1” 是表示选择所有 “where 1=2”所有不选,
如:
if @strWhere !=''
begin
set @strSQL = 'select count(*) as Total from [' + @tblName + '] where ' + @strWhere
end
else
begin
set @strSQL = 'select count(*) as Total from [' + @tblName + ']'
end
咱们能够直接写成
错误!未找到目录项。
set @strSQL = 'select count(*) as Total from [' + @tblName + '] where 1=1 安定 '+ @strWhere 二、收缩数据库
--重建索引
DBCC REINDEX
DBCC INDEXDEFRAG
--收缩数据和日志
DBCC SHRINKDB
DBCC SHRINKFILE
三、压缩数据库
dbcc shrinkdatabase(dbname)
四、转移数据库给新用户以已存在用户权限
exec sp_change_users_login 'update_one','newname','oldname'
go
五、检查备份集
RESTORE VERIFYONLY from disk='E:\dvbbs.bak'
六、修复数据库
ALTER DATABASE [dvbbs] SET SINGLE_USER
GO
DBCC CHECKDB('dvbbs',repair_allow_data_loss) WITH TABLOCK
GO
ALTER DATABASE [dvbbs] SET MULTI_USER
GO
七、日志清除
SET NOCOUNT ON
DECLARE @LogicalFileName sysname,
@MaxMinutes INT,
@NewSize INT
USE tablename -- 要操做的数据库名
SELECT @LogicalFileName = 'tablename_log', -- 日志文件名
@MaxMinutes = 10, -- Limit on time allowed to wrap log.
@NewSize = 1 -- 你想设定的日志文件的大小(M)
Setup / initialize
DECLARE @OriginalSize int
SELECT @OriginalSize = size
FROM sysfiles
WHERE name = @LogicalFileName
SELECT 'Original Size of ' + db_name() + ' LOG is ' +
CONVERT(VARCHAR(30),@OriginalSize) + ' 8K pages or ' +
CONVERT(VARCHAR(30),(@OriginalSize*8/1024)) + 'MB'
FROM sysfiles
WHERE name = @LogicalFileName
CREATE TABLE DummyTrans
(DummyColumn char (8000) not null)
DECLARE @Counter INT,
@StartTime DATETIME,
@TruncLog VARCHAR(255)
SELECT @StartTime = GETDATE(),
@TruncLog = 'BACKUP LOG ' + db_name() + ' WITH TRUNCATE_ONLY'
DBCC SHRINKFILE (@LogicalFileName, @NewSize)
EXEC (@TruncLog)
-- Wrap the log if necessary.
WHILE @MaxMinutes > DATEDIFF (mi, @StartTime, GETDATE()) -- time has not expired
AND @OriginalSize = (SELECT size FROM sysfiles WHERE name = @LogicalFileName)
AND (@OriginalSize * 8 /1024) > @NewSize
BEGIN -- Outer loop.
SELECT @Counter = 0
WHILE ((@Counter < @OriginalSize / 16) AND (@Counter < 50000))
BEGIN -- update
INSERT DummyTrans VALUES ('Fill Log') DELETE DummyTrans
SELECT @Counter = @Counter + 1
END
EXEC (@TruncLog)
END
SELECT 'Final Size of ' + db_name() + ' LOG is ' +
CONVERT(VARCHAR(30),size) + ' 8K pages or ' +
CONVERT(VARCHAR(30),(size*8/1024)) + 'MB'
FROM sysfiles
WHERE name = @LogicalFileName
DROP TABLE DummyTrans
SET NOCOUNT OFF
八、说明:更改某个表
exec sp_changeobjectowner 'tablename','dbo'
九、存储更改所有表
CREATE PROCEDURE dbo.User_ChangeObjectOwnerBatch
@OldOwner as NVARCHAR(128),
@NewOwner as NVARCHAR(128)
AS
DECLARE @Name as NVARCHAR(128)
DECLARE @Owner as NVARCHAR(128)
DECLARE @OwnerName as NVARCHAR(128)
DECLARE curObject CURSOR FOR
select 'Name' = name,
'Owner' = user_name(uid)
from sysobjects
where user_name(uid)=@OldOwner
order by name
OPEN curObject
FETCH NEXT FROM curObject INTO @Name, @Owner
WHILE(@@FETCH_STATUS=0)
BEGIN
if @Owner=@OldOwner
begin
set @OwnerName = @OldOwner + '.' + rtrim(@Name)
exec sp_changeobjectowner @OwnerName, @NewOwner
end
-- select @name,@NewOwner,@OldOwner
FETCH NEXT FROM curObject INTO @Name, @Owner
END
close curObject
deallocate curObject
GO
十、SQL SERVER中直接循环写入数据
declare @i int
set @i=1
while @i<30
begin
insert into test (userid) values(@i)
set @i=@i+1
end
案例:
有以下表,要求就裱中全部沒有及格的成績,在每次增長0.1的基礎上,使他們剛好及格:
Name score
Zhangshan 80
Lishi 59
Wangwu 50
Songquan 69
while((select min(score) from tb_table)<60)
begin
update tb_table set score =score*1.01
where score<60
if (select min(score) from tb_table)>60
break
else
continue
end
数据开发-经典
1.按姓氏笔画排序:
Select * From TableName Order By CustomerName Collate Chinese_PRC_Stroke_ci_as //从少到多
2.数据库加密:
select encrypt('原始密码')
select pwdencrypt('原始密码')
select pwdcompare('原始密码','加密后密码') = 1--相同;不然不相同 encrypt('原始密码')
select pwdencrypt('原始密码')
select pwdcompare('原始密码','加密后密码') = 1--相同;不然不相同
3.取回表中字段:
declare @list varchar(1000),
@sql nvarchar(1000)
select @list=@list+','+b.name from sysobjects a,syscolumns b where a.id=b.id and a.name='表A'
set @sql='select '+right(@list,len(@list)-1)+' from 表A'
exec (@sql)
4.查看硬盘分区:
EXEC master..xp_fixeddrives
5.比较A,B表是否相等:
if (select checksum_agg(binary_checksum(*)) from A)
=
(select checksum_agg(binary_checksum(*)) from B)
print '相等'
else
print '不相等'
6.杀掉全部的事件探察器进程:
DECLARE hcforeach CURSOR GLOBAL FOR SELECT 'kill '+RTRIM(spid) FROM master.dbo.sysprocesses
WHERE program_name IN('SQL profiler',N'SQL 事件探查器')
EXEC sp_msforeach_worker '?'
7.记录搜索:
开头到N条记录
Select Top N * From 表
-------------------------------
N到M条记录(要有主索引ID)
Select Top M-N * From 表 Where ID in (Select Top M ID From 表) Order by ID Desc
----------------------------------
N到结尾记录
Select Top N * From 表 Order by ID Desc
案例
例如1:一张表有一万多条记录,表的第一个字段 RecID 是自增加字段, 写一个SQL语句, 找出表的第31到第40个记录。
select top 10 recid from A where recid not in(select top 30 recid from A)
分析:若是这样写会产生某些问题,若是recid在表中存在逻辑索引。
select top 10 recid from A where……是从索引中查找,然后面的select top 30 recid from A则在数据表中查找,这样因为索引中的顺序有可能和数据表中的不一致,这样就致使查询到的不是原本的欲获得的数据。
解决方案
1, 用order by select top 30 recid from A order by ricid 若是该字段不是自增加,就会出现问题
2, 在那个子查询中也加条件:select top 30 recid from A where recid>-1
例2:查询表中的最后以条记录,并不知道这个表共有多少数据,以及表结构。
set @s = 'select top 1 * from T where pid not in (select top ' + str(@count-1) + ' pid from T)'
print @s exec sp_executesql @s
9:获取当前数据库中的全部用户表
select Name from sysobjects where xtype='u' and status>=0
10:获取某一个表的全部字段
select name from syscolumns where id=object_id('表名')
select name from syscolumns where id in (select id from sysobjects where type = 'u' and name = '表名')
两种方式的效果相同
11:查看与某一个表相关的视图、存储过程、函数
select a.* from sysobjects a, syscomments b where a.id = b.id and b.text like '%表名%'
12:查看当前数据库中全部存储过程
select name as 存储过程名称 from sysobjects where xtype='P'
13:查询用户建立的全部数据库
select * from master..sysdatabases D where sid not in(select sid from master..syslogins where name='sa')
或者
select dbid, name AS DB_NAME from master..sysdatabases where sid <> 0x01
14:查询某一个表的字段和数据类型
select column_name,data_type from information_schema.columns
where table_name = '表名'
15:不一样服务器数据库之间的数据操做
--建立连接服务器
exec sp_addlinkedserver 'ITSV ', ' ', 'SQLOLEDB ', '远程服务器名或ip地址 '
exec sp_addlinkedsrvlogin 'ITSV ', 'false ',null, '用户名 ', '密码 '
--查询示例
select * from ITSV.数据库名.dbo.表名
--导入示例
select * into 表 from ITSV.数据库名.dbo.表名
--之后再也不使用时删除连接服务器
exec sp_dropserver 'ITSV ', 'droplogins '
--链接远程/局域网数据(openrowset/openquery/opendatasource)
--一、openrowset
--查询示例
select * from openrowset( 'SQLOLEDB ', 'sql服务器名 '; '用户名 '; '密码 ',数据库名.dbo.表名)
--生成本地表
select * into 表 from openrowset( 'SQLOLEDB ', 'sql服务器名 '; '用户名 '; '密码 ',数据库名.dbo.表名)
--把本地表导入远程表
insert openrowset( 'SQLOLEDB ', 'sql服务器名 '; '用户名 '; '密码 ',数据库名.dbo.表名)
select *from 本地表
--更新本地表
update b
set b.列A=a.列A
from openrowset( 'SQLOLEDB ', 'sql服务器名 '; '用户名 '; '密码 ',数据库名.dbo.表名)as a inner join 本地表 b
on a.column1=b.column1
--openquery用法须要建立一个链接
--首先建立一个链接建立连接服务器
exec sp_addlinkedserver 'ITSV ', ' ', 'SQLOLEDB ', '远程服务器名或ip地址 '
--查询
select *
FROM openquery(ITSV, 'SELECT * FROM 数据库.dbo.表名 ')
--把本地表导入远程表
insert openquery(ITSV, 'SELECT * FROM 数据库.dbo.表名 ')
select * from 本地表
--更新本地表
update b
set b.列B=a.列B
FROM openquery(ITSV, 'SELECT * FROM 数据库.dbo.表名 ') as a
inner join 本地表 b on a.列A=b.列A
--三、opendatasource/openrowset
SELECT *
FROM opendatasource( 'SQLOLEDB ', 'Data Source=ip/ServerName;User ID=登录名;Password=密码 ' ).test.dbo.roy_ta
--把本地表导入远程表
insert opendatasource( 'SQLOLEDB ', 'Data Source=ip/ServerName;User ID=登录名;Password=密码 ').数据库.dbo.表名
select * from 本地表
SQL Server基本函数
SQL Server基本函数
1.字符串函数 长度与分析用
1,datalength(Char_expr) 返回字符串包含字符数,但不包含后面的空格
2,substring(expression,start,length) 取子串,字符串的下标是从“1”,start为起始位置,length为字符串长度,实际应用中以len(expression)取得其长度
3,right(char_expr,int_expr) 返回字符串右边第int_expr个字符,还用left于之相反
4,isnull( check_expression , replacement_value )若是check_expression為空,則返回replacement_value的值,不為空,就返回check_expression字符操做类
5,Sp_addtype 自定義數據類型
例如:EXEC sp_addtype birthday, datetime, 'NULL'
6,set nocount {on|off}
使返回的结果中不包含有关受 Transact-SQL 语句影响的行数的信息。若是存储过程当中包含的一些语句并不返回许多实际的数据,则该设置因为大量减小了网络流量,所以可显著提升性能。SET NOCOUNT 设置是在执行或运行时设置,而不是在分析时设置。
SET NOCOUNT 为 ON 时,不返回计数(表示受 Transact-SQL 语句影响的行数)。
SET NOCOUNT 为 OFF 时,返回计数
常识
在SQL查询中:from后最多能够跟多少张表或视图:256
在SQL语句中出现 Order by,查询时,先排序,后取
在SQL中,一个字段的最大容量是8000,而对于nvarchar(4000),因为nvarchar是Unicode码。
SQLServer2000同步复制技术实现步骤
1、 预备工做
1.发布服务器,订阅服务器都建立一个同名的windows用户,并设置相同的密码,作为发布快照文件夹的有效访问用户
--管理工具
--计算机管理
--用户和组
--右键用户
--新建用户
--创建一个隶属于administrator组的登录windows的用户(SynUser)
2.在发布服务器上,新建一个共享目录,作为发布的快照文件的存放目录,操做:
个人电脑--D:\ 新建一个目录,名为: PUB
--右键这个新建的目录
--属性--共享
--选择"共享该文件夹"
--经过"权限"按纽来设置具体的用户权限,保证第一步中建立的用户(SynUser) 具备对该文件夹的全部权限
--肯定
3.设置SQL代理(SQLSERVERAGENT)服务的启动用户(发布/订阅服务器均作此设置)
开始--程序--管理工具--服务
--右键SQLSERVERAGENT
--属性--登录--选择"此帐户"
--输入或者选择第一步中建立的windows登陆用户名(SynUser)
--"密码"中输入该用户的密码
4.设置SQL Server身份验证模式,解决链接时的权限问题(发布/订阅服务器均作此设置)
企业管理器
--右键SQL实例--属性
--安全性--身份验证
--选择"SQL Server 和 Windows"
--肯定
5.在发布服务器和订阅服务器上互相注册
企业管理器
--右键SQL Server组
--新建SQL Server注册...
--下一步--可用的服务器中,输入你要注册的远程服务器名 --添加
--下一步--链接使用,选择第二个"SQL Server身份验证"
--下一步--输入用户名和密码(SynUser)
--下一步--选择SQL Server组,也能够建立一个新组
--下一步--完成
6.对于只能用IP,不能用计算机名的,为其注册服务器别名(此步在实施中没用到)
(在链接端配置,好比,在订阅服务器上配置的话,服务器名称中输入的是发布服务器的IP)
开始--程序--Microsoft SQL Server--客户端网络实用工具
--别名--添加
--网络库选择"tcp/ip"--服务器别名输入SQL服务器名
--链接参数--服务器名称中输入SQL服务器ip地址
--若是你修改了SQL的端口,取消选择"动态决定端口",并输入对应的端口号
2、 正式配置
一、配置发布服务器
打开企业管理器,在发布服务器(B、C、D)上执行如下步骤:
(1) 从[工具]下拉菜单的[复制]子菜单中选择[配置发布、订阅服务器和分发]出现配置发布和分发向导
(2) [下一步] 选择分发服务器 能够选择把发布服务器本身做为分发服务器或者其余sql的服务器(选择本身)
(3) [下一步] 设置快照文件夹
采用默认\\servername\Pub
(4) [下一步] 自定义配置
能够选择:是,让我设置分发数据库属性启用发布服务器或设置发布设置
否,使用下列默认设置(推荐)
(5) [下一步] 设置分发数据库名称和位置 采用默认值
(6) [下一步] 启用发布服务器 选择做为发布的服务器
(7) [下一步] 选择须要发布的数据库和发布类型
(8) [下一步] 选择注册订阅服务器
(9) [下一步] 完成配置
二、建立出版物
发布服务器B、C、D上
(1)从[工具]菜单的[复制]子菜单中选择[建立和管理发布]命令
(2)选择要建立出版物的数据库,而后单击[建立发布]
(3)在[建立发布向导]的提示对话框中单击[下一步]系统就会弹出一个对话框。对话框上的内容是复制的三个类型。咱们如今选第一个也就是默认的快照发布(其余两个你们能够去看看帮助)
(4)单击[下一步]系统要求指定能够订阅该发布的数据库服务器类型,
SQLSERVER容许在不一样的数据库如 orACLE或ACCESS之间进行数据复制。
可是在这里咱们选择运行"SQL SERVER 2000"的数据库服务器
(5)单击[下一步]系统就弹出一个定义文章的对话框也就是选择要出版的表
注意: 若是前面选择了事务发布 则再这一步中只能选择带有主键的表
(6)选择发布名称和描述
(7)自定义发布属性 向导提供的选择:
是 我将自定义数据筛选,启用匿名订阅和或其余自定义属性
否 根据指定方式建立发布 (建议采用自定义的方式)
(8)[下一步] 选择筛选发布的方式
(9)[下一步] 能够选择是否容许匿名订阅
1)若是选择署名订阅,则须要在发布服务器上添加订阅服务器
方法: [工具]->[复制]->[配置发布、订阅服务器和分发的属性]->[订阅服务器] 中添加
不然在订阅服务器上请求订阅时会出现的提示:改发布不容许匿名订阅
若是仍然须要匿名订阅则用如下解决办法
[企业管理器]->[复制]->[发布内容]->[属性]->[订阅选项] 选择容许匿名请求订阅
2)若是选择匿名订阅,则配置订阅服务器时不会出现以上提示
(10)[下一步] 设置快照 代理程序调度
(11)[下一步] 完成配置
当完成出版物的建立后建立出版物的数据库也就变成了一个共享数据库
有数据
srv1.库名..author有字段:id,name,phone,
srv2.库名..author有字段:id,name,telphone,adress
要求:
srv1.库名..author增长记录则srv1.库名..author记录增长
srv1.库名..author的phone字段更新,则srv1.库名..author对应字段telphone更新
--*/
--大体的处理步骤
--1.在 srv1 上建立链接服务器,以便在 srv1 中操做 srv2,实现同步
exec sp_addlinkedserver 'srv2','','SQLOLEDB','srv2的sql实例名或ip'
exec sp_addlinkedsrvlogin 'srv2','false',null,'用户名','密码'
go
--2.在 srv1 和 srv2 这两台电脑中,启动 msdtc(分布式事务处理服务),而且设置为自动启动
。个人电脑--控制面板--管理工具--服务--右键 Distributed Transaction Coordinator--属性--启动--并将启动类型设置为自动启动
go
--而后建立一个做业定时调用上面的同步处理存储过程就好了
企业管理器
--管理
--SQL Server代理
--右键做业
--新建做业
--"常规"项中输入做业名称
--"步骤"项
--新建
--"步骤名"中输入步骤名
--"类型"中选择"Transact-SQL 脚本(TSQL)"
--"数据库"选择执行命令的数据库
--"命令"中输入要执行的语句: exec p_process
--肯定
--"调度"项
--新建调度
--"名称"中输入调度名称
--"调度类型"中选择你的做业执行安排
--若是选择"反复出现"
--点"更改"来设置你的时间安排
而后将SQL Agent服务启动,并设置为自动启动,不然你的做业不会被执行
设置方法:
个人电脑--控制面板--管理工具--服务--右键 SQLSERVERAGENT--属性--启动类型--选择"自动启动"--肯定.
--3.实现同步处理的方法2,定时同步
--在srv1中建立以下的同步处理存储过程
create proc p_process
as
--更新修改过的数据
update b set name=i.name,telphone=i.telphone
from srv2.库名.dbo.author b,author i
where b.id=i.id and
(b.name <> i.name or b.telphone <> i.telphone)
--插入新增的数据
insert srv2.库名.dbo.author(id,name,telphone)
select id,name,telphone from author i
where not exists(
select * from srv2.库名.dbo.author where id=i.id)
--删除已经删除的数据(若是须要的话)
delete b
from srv2.库名.dbo.author b
where not exists(
select * from author where id=b.id)
go
转载自:http://www.chengxuyuans.com/oracle/66221.html