Oracle Databse SQL 程序


程序块

在这之前,我们所有的sql语句都是一句一句执行的,如果我们把很多事情看作一个整体提交执行的话,必须使用程序块。

声明部分:声名变量及初始化

关键字:declare

执行部分:存放所有可执行的代码,这些代码包含在begin/end中

关键字:begin end

每个指令结束用;表示,--表示注释

--这是一个示例

declare

i number:=5; y number:=6;

begin

i:=i+y;

dbms_output.put_line(i);

end;

/

流程控制

--条件if......then...elseif.. .end if;

declare

i number:=50;

begin

if i=50

then dbms_output.put_line(i);

elsif i<50

then dbms_output.put_line(0);

end if;

end;

/

-----使用loop循环(exit when 退出条件)

declare

i number;

begin

i:=0;

loop

exit when i=10;

dbms_output.put_line(i);

i:=i+1;

end loop;

end;

-----使用while-loop循环

declare

i number;

begin

i:=0;

while i<10

loop

dbms_output.put_line(i);

i:=i+1;

end loop;

end;

/

-----使用for-loop循环

begin

for i in 1..10

loop

dbms_output.put_line(i);

end loop;

end;

/

-----使用for-loop反序循环

begin

for i in REVERSE 1..10

loop

dbms_output.put_line(i);

end loop;

end;

字符串函数

函数名: ASCII(char)

含义: 返回与指定的字符对应的十进制数

示例: select ascii('孟') from dual;

结果: 50127

函数名: CHR(int)

含义: 给出整数,返回对应的字符

示例: select chr(50127) from dual;

结果: 孟

函数名: CONCAT(string,string)

含义: 连接两个字符串

示例: select concat('我是','孟庆晨') from dual;

结果: 我是孟庆晨

函数名: INITCAP(string)

含义: 返回字符串并将字符串的第一个字母变为大写

示例: select INITCAP('aaa') from dual;

结果: Aaa

函数名: INSTR(被搜索字符串,搜索的字符串,搜索的开始位置默认为1,第几次出现默认为1)

含义: 在一个字符串中搜索指定的字符,返回发现指定的字符的位置

示例: select INSTR('我是孟庆晨','孟',1,1) from dual;

结果: 3

函数名: LENGTH(string)

含义: 返回字符串的长度

示例: select length(‘孟庆晨’) from dual ;

结果: 3

函数名: LOWER(string)

含义: 小写形式

示例: select lower(‘AAA’) from dual

结果: aaa

函数名: UPPER

含义: 大写形式

示例: select upper(‘aaa’) from dual ;

结果: AAA

函数名: RPAD & LPAD

含义: 黏贴字符串到目标字符串左右

示例: select lpad(‘a’,10,’*’) from dual ;

结果: *********a

函数名: ltrim & rtrim

含义: 删除左边(右边)的字符串

示例: select ltrim(‘abc’,’a’) from dual ;

结果: bc

函数名: substr

含义: 取字符串(原字符串,第几个开始,取几个)

示例: select substring(‘abcdefg’,3,4) from dual

结果: cdef

函数名: REPLACE(string,string,string)

含义: 替换字符串

示例: select replace(‘abcde’ , ‘abc’ , ‘aaa’ ) from dual ;

结果: aaade

数学函数

函数名: abs

含义: 返回指定值的绝对值

示例: select abs(-10) from dual

结果: 10

异常处理

自定义异常处理     1. 定义异常处理     定义异常处理的语法如下:     declare         异常名 exception;

begin     2. 触发异常处理     触发异常处理的语法如下:     raise 异常名;     3. 处理异常     触发异常处理后,可以定义异常处理部分,语法如下:     Exception     When 异常名1 then        异常处理语句段1;     When 异常名2 then        异常处理语句段2;

end;

小技巧

raise_application_error(错误代码,错误原因) 函数可以直接抛异常

其中错误代码为-20000到-20999之间,错误原因为2000个以内的字符

set linesize 800;

set linesize 可以一行的字符数,默认80

设置每行为800个字符,set linesize 800;

2.7.2、L(list)

此命令可以显示SQL缓冲区中的内容

相当于上下键来显示输入过的SQL语句

2.7.3、run / r

以上三个命令完成的功能是一样的,重新运行缓存区中的语句

2.7.4、save

Save命令可以将缓存区中的语句保存到文件

save c:\sql.sql;

2.7.5、get

Get可将文件中的sql读取出来

get c:sql.sql

2.7.6、ed

可以采用记事本编辑sql语句

ed

2.7.7、如何直接运行文件中的sql语句

@c:\sql.sql

2.10.1、lower

查询员工信息,将姓名转换成小写

select empno,lower(ename) from emp ;

2.10.2、upper

select empno,upper(ename) from emp ;

2.10.3、substr

l  查询员工,只显示员工姓名的前三个字符

select empno,substr(ename,1,3) from emp;

2.10.4、length

l  查询员工,取得员工姓名的长度

select empno,length(ename) as 长度 from   emp;

2.10.5、trim

Trim会去除头尾空格,不会去除中间的空格

select empno,trim(ename) from emp ;

2.10.6、to_date

l  查询入职日期大于1980年01月01日

select empno,ename from emp where HIREDATE >  to_date('1980-01-01','YYYY-MM-DD');

To_date可以将字符串转换成日期,具体格式to_date(字符串,匹配格式)

日期格式的说明

控制符

说明

YYYY

表示年

MM

表示月

DD

表示日

HH12,HH24

表示12小时制,表示24小时制

MI

表示分

SS

表示秒

2.10.7、to_char

l  查询所有员工,将入职日期格式成年月日时分秒方式

select empno,ename ,to_char(HIREDATE,'YYYY-MM-DD') as 雇佣日期 from   emp;

l  查询所有员工,小数保留两位,采用逗号分组

select empno,ename ,to_char(sal,'$999,999.00') from   emp;

将数字转换成字符串,格式

控制符

说明

9

表示一位数字

0

位数不够可以补零

$

美元符

L

本地货币符号

.

显示小数

,

显示千分位

2.10.8、to_number

将字符串转换成数值

select * from emp where sal>to_number('1,000', '999,999');

2.10.9、nvl

l  取得员工的全部薪水,薪水+津贴

select empno,ename,sal+comm from emp ;---错误

以上结果不正确,主要原因是津贴(comm)字段为null,所以无法计算,所以正确的做法是将津贴先转换成0,再计算。可以使用Oracle提供的nvl,该函数的语法格式为:nvl(表达式1,表达式2),表达式1:指的是字段名称;表达式2:指的是将该字段的null转换成的值

l  采用nvl函数,取得员工的全部薪水,薪水+津贴

select empno,ename,sal+nvl(comm,0) as 全部薪水  from emp ;

以上结果是正确的,在做表设计的时候,关于数值字段最好不允许为null,可以设置缺省值为0

2.10.10、case … when … then …end

l  如果job为MANAGER工资涨50%,如果是SALESMAN工资涨20%

select empno,ename ,    case job when 'MANAGER' then sal*1.5    when 'SALESMAN' then sal*1.2 end as newsal from emp ;

具体用法case 字段 when 条件 then 。。。。when… then….. end

2.10.11、Decode

同case 。。 when … then ….end

select empno,ename   ,decode(job,'MANAGER',sal*1.5,'SALESMAN',sal*1.2) as 薪水 from   emp ;

Decode语法:decode(字段,条件,执行的运算)

2.10.12、round

round主要可以完成四舍五入

select round(sal/100.0) from emp;

注意:dual是Oracle提供的,主要为了方便因为使用select那么from后面需要跟上表

2.11、聚合函数

count

取得记录数

sum

求和

Avg

取平均

Max

取最大的数

min

取最小的数

2.11.1、Count

l  取得所有的员工数

select count(*) from emp;

采用count(*)会取的记录,忽略null

l  取得津贴不为null的员工数

select count(*) from emp where comm  is not    null;

采用count(字段名称),该字段不会null的个数

l  取得工作岗位的个数

select count(job) from emp;

Distinct可以过滤重复的记录

select count(distinct job) from emp;

2.11.2、sum

Sum可以取得某一列的和,但忽略null的行,sum里可以放置表达式

l  取得薪水的合计数

select sum(sal) as sal_total from emp;

l  取得薪水的合计数(薪水+津贴)

从计算结果来看,不正确,原因在于comm字段有null,所以无法计算,sum会忽略掉。正确的做法,是将comm字段先转换成0再sum,如下所示:

l  取得薪水的合计数(薪水+津贴)

select sum(sal+nvl(comm,0)) as sal_total from emp;

正确

2.11.3、avg

取得某列或表达式的平均值

l  取得平均薪水

select avg(sal) from emp;

2.11.4、max

Max取得指定列的最大值

l  取得最高的薪水

select max(sal) as 薪水 from emp;

l  取得最晚入职的员工

select max(to_char(hiredate,'YYYY-MM-DD')) from emp;

2.11.5、min

取得指定列的最小值

l  取得最低薪水

select min(sal) from emp;

2.11.6、组合聚合函数

可以在select组合使用聚合函数

l  取得员工数,工资合计,平均工资,最高工资,最低工资

select count(*) as 员工数,sum(sal) as 工资合计 ,avg(sal) as 平均工资 , max(sal) as 最高薪水,min(sal) as 最低薪水 from emp ;

2.12、分组查询

分组主要涉及到两个子句:group by和having

2.12.1、group by

l  取得每个岗位的工资合计,要求显示出岗位名称和每个岗位的工资合计

select sum(sal) ,job    from emp group by job;

采用group by时,聚合函数前的所有字段必须参与分组

采用group by时,如果存在order by,那么order by必须放到group by后面

以上是不正确的

l  取得每个岗位的工资合计,要求显示出部门代码,岗位名称和每个岗位的工资合计

2.12.2、having

如果想按条件取得分组中的数据那么需要使用having

l  取得平均工资大于2000的岗位

select job,avg(sal) from emp group by job having   avg(sal) >2000;

分组函数的执行顺序:

a)       先根据条件查询数据

b)       对记录分组

c)        采用having进行过滤,选择出正确的数据

2.12.3、select语句总结

完整的select语句格式如下

Select *,列名

From 表名

Where …..

Group by ……

Having …….

Order by ……..

以上语句执行顺序

a)       首先执行where语句来过滤原始记录

b)       执行group by分组

c)        执行having过滤

d)       执行select选出数据

e)       最后执行order by排序

关键点:把子查询作为一张表来用

2.15、union、minus

2.15.1、Union可以合并结果集(加)

select deptno,dname from dept

union

select empno   ,ename from emp;

2.15.1、minus可移除结果集(减)

l  查询部门编号为10和20的员工,移除薪水小于2000的

select empno,ename from emp where deptno=10 or

minus

select empno,ename from emp where sal<2000;

相当于:select empno, ename, sal from emp where deptno in(10, 20) and sal >=2000;

2.16、rownum的使用

Oracle提供了一个rownum隐含字段,每个表都有,rownum是每条记录的行号,从1开始顺序递增

2.16.1、隐含字段rownum

select rownum ,empno,ename from emp;

2.16.2、显示出前五条数据

select empno ,ename from emp where rownum<=5;

2.16.3、显示大于5行以后的数据

select empno ,ename from emp where rownum>=5;

以上语句,无法查询到符合条件的数据,rownum只支持<=,不支持= 或>= 或>

只支持=1

select empno ,ename from emp where rownum=1;-这条可以

2.16.4、显示薪水最高的前5为员工

上面的结果不是预期的结果,因为rownum在数据集形成时已经确定,采用order by 排序不会给便rownum的值,采用如下方式可以取得前5名:

select rownum ,empno,ename

from

(select   empno,ename from emp order by sal desc) e

Where

rownum<=5;

2.16.5、采用rownum分页查询

分页查询主要为了提高效率,不是一次性查询出所有的数据,而是部分查询,如:每次查询5条

第一页:1~5

第二页:6~10

第三页:。。。。。。

因为rownum不支持>=,必须采用3层嵌套的sql来进行分页,嵌套的目的就是转换rownum,支持大于等于

select empno, ename, sal from

(select rownum   r, empno, ename, sal from

(select rownum ,empno, ename, sal from

emp order by   sal desc

)

where rownum   <=10

)

where r>5;

以上使用3层的select嵌套完成分页,嵌套的目的就是将rownum转换成一个字段r,r代表了一个字段,r不再是隐含字段,r作为普通字段,所以我们就可以对r进行任何操作

如果忽略了插入的字段,那么它会严格按照表中字段的顺序,包括类型必须符合,这中方式存在缺陷,如果表中位置发生改变,将会影响到insert语句。可以显示的设置某个值为null

l  指定字段插入

insert into emp (empno,ename) values(3000,'kyle');

建议使用以上insert方式,此种方式存在优点,当数据库表中的字段顺序发生改变,不会影响到我们的insert语句

l  表内容复制---记住

create table new_emp  as  select * from emp;

以上语句可以自动建立一个表,将所有的数据拷贝到新表中

l  如何将查询出的数据插入到已经存在的表中(insert into 新表名 select * from 表名)

insert into   new_emp select * from emp; ----要求表必须存在

本示例同create table new_emp as select ……的区别在于,本示例不会创建表,只向已经存在的表中复制数据,而前者会自动创建表。

2.17.2、update

Update可以更新数据,它可以更具条件更新

l  语法格式

Update 表名 set 字段名称=更新的值,……… where ………..

l  更新全部数据

将所有的工资全部改为1000

update new_emp set sal=1000 ;

如果job为MANAGER,薪水上涨50%

update new_emp set sal=sal+(sal*0.5) where job='MANAGER';

可以更新多个字段,字段间用逗号隔开

update new_emp set sal=10000 ,comm=5000 where   job='MANAGER' ;

2.17.3、delete

Delete可以删除一个或多个数据

l  语法格式

Delete from 表名 where …….

l  删除部门数据

删除津贴为null的记录

delete from new_emp where empno=7782;

delete from new_emp where comm is null;

l  删除全部数据

delete from new_emp;

2.18、事务概述

北京数据库

金额:10000

深圳数据库

金额:

向深圳数据库转账8000,必须保障北京数据库减少8000,深圳数据库增加8000,这两项操作必须全部成功,如何保障?需要事务

事务可以保证多个操作原子性,要么全成功,要么全失败。对于数据库来说事务保证批量的sql要么全成功,要么全失败。事务具有四个特征ACID

a)       原子性

b)       一致性

c)        隔离性

d)       持续性

事务中存在一些概念:

a)       事务(Transaction):一批操作(一组sql)

b)       开启事务(Begin Transaction)

c)        回滚事务(rollback Transaction)--Oracle---rollback

d)       提交事务(commit transaction)----Oracle--commit

当执行DML语句是其实就是开启一个事务

关于事务的回滚需要注意:只能回滚insert、delete和update语句,不能回滚select(回滚select没有任何意义),对于create、drop、alter这些无法回滚

2.19、表

2.19.1、创建表

l  语法格式

Create table 表名(

列名称 类型,

…………….,

…………….

l  Oracle常用数据类型

类型

描述

Char(长度)

定长字符串,存储空间大小固定,适合作为主键或外间

Varchar2(长度)

变长字符串,存储空间等于实际数据空间

Number(位数,小数位)

数值型

Date

日期型

l  建立学生信息表

组要涉及的字段:学号、姓名、性别、出生日期,email、班级标识

create table t_student (

student_id   number(10)  ,

student_name   varchar2(20),

sex   char(2),

birthday   date,

email   varchar2(20),

classes_id   number(3),

primary key(student_id)

)

l  建立表加入默认值

性别加入默认值为“男“,出生日期加入默认值为当前时间

create table t_student (

student_id   number(10),

student_name   varchar2(20),

sex   char(2) default '男',

birthday   date default sysdate,

email   varchar2(20),

classes_id   number(3)

)

2.19.2、创建表加入约束

l  常见的约束

a)       非空约束,not null

b)       唯一约束,unique key

c)        主键约束,primary key

d)       外键约束,foreign key

e)       自定义检查约束,check

l  非空约束,not null

非空约束可以指定某个字段不为空,如:学生姓名不能为空

create table t_student (

student_id   number(10),

student_name   varchar2(20) not null,

sex   char(2) default '男',

birthday   date default sysdate,

email   varchar2(20),

classes_id   number(3)

)

以上,我们可以为约束起个名字,建表语句如下:

create table t_student (

student_id   number(10),

student_name   varchar2(20) constraint stu_name_not_null not null,

sex   char(2) default '男',

birthday   date default sysdate,

email   varchar2(20),

classes_id   number(3)

)

l  唯一约束,unique key

唯一约束,可以使某一个字段的值不能重复,如:email不能重复

create table t_student (

student_id   number(10),

student_name   varchar2(20),

sex   char(2) default '男',

birthday   date default sysdate,

email varchar2(20) unique,

classes_id   number(3)

)

同样可以为唯一性约束起一个约束名称

create table t_student (

student_id   number(10),

student_name   varchar2(20),

sex   char(2) default '男',

birthday date default sysdate,

email   varchar2(20) constraint email_unique unique,

classes_id number(3)

)

以上约束是在字段后面,这种方式称为字段级约束,另外这种约束也可以加到字段定义的后面,此时称为表级约束

create table t_student (

student_id   number(10),

student_name   varchar2(20),

sex   char(2) default '男',

birthday   date default sysdate,

email   varchar2(20),

classes_id   number(3),

constraint email_uqinue unique(email)

)

l  主键约束,primary key

每个表都应该具有主键,主键可以标识一条记录的唯一性,主键分为单一主键和复合主键

单一主键:一个字段构成主键

复合:多个字段构成主键,一般不建议使用

create table t_student (

student_id   number(10)  primary   key,

student_name   varchar2(20),

sex   char(2),

birthday   date,

email   varchar2(20),

classes_id   number(3)

)

以上也已采用表级约束

create table t_student (

student_id   number(10),

student_name   varchar2(20),

sex   char(2),

birthday   date,

email varchar2(20),

classes_id   number(3),

constraint stu_pk_id primary key(student_id)

)

复合主键示例

create table t_student (

student_id   number(10),

student_name   varchar2(20),

sex   char(2),

birthday   date,

email   varchar2(20),

classes_id   number(3),

constraint   stu_pk_id primary key(student_id,student_name)

)

l  外键约束,foreign key

外键通常建立在两个字段或两个表之间,主要为了保证参照完整性,如果一表中的某个字段为外键,那么这个字段的值全部来源于另一表的主键,例如:emp表中的deptno是一个外键,它的值全部来源于dept表的主键字段deptno

如果向emp表中加入一条数据,指定deptno为60,将会出现如下错误:

出现错误的原因就是,emp表中的deptno是外键,而60在dept表中不存在,所以无法参照60这个部门

如果emp表中的deptno没有设置为非空,虽然他是外键,但仍然可以插入null值,如果设置了外键,最好设置这个外键这段为非空

删除dept表中的记录,将会出现如下问题

出现问题的原因是:emp表中参照了部门编号10,如果想删除必须先将emp表中引用部门编号10的员工删除,再来删除dept表中的部门编号10

对t_student表中的classes_id如何创建外键约束:

首先加入t_classes表

Create table t_classes (

Id number(3),

Name   varchar2(2),

Constraint   t_classes_pk_id primary key(id)

)

建立外键

create table t_student (

student_id   number(10),

student_name   varchar2(20),

sex   char(2),

birthday   date,

email   varchar2(20),

classes_id   number(3) references t_classes(id),

constraint   stu_pk_id primary key(student_id,student_name)

)

也可以采用表级约束

create table t_student (

student_id   number(10),

student_name   varchar2(20),

sex   char(2),

birthday date,

email   varchar2(20),

classes_id   number(3) not null,

constraint   stu_pk_id primary key(student_id,student_name),

constraint stu_fk_classes_id foreign key(classes_id)   references t_classes(id)

)

外键一定要来源于主键

l  自定义检查约束,check

使用check可以检查表中的字段,是否复合某一个表达式,如:性别只能为“男”或“女”

create table t_student (

student_id   number(10),

student_name   varchar2(20),

sex   char(2) ,

birthday   date,

email   varchar2(20),

classes_id   number(3) not null,

constraint   stu_pk_id primary key(student_id,student_name),

constraint stu_fk_classes_id foreign key(classes_id) references t_classes(id),

constraint   stu_check_sex check(sex in('男','女'))

)

Check支持常见的表达式,但check很少使用,通常关于验证都在应用程序中做,而不再数据库中作

2.19.3、T_student完整示例

create table t_student (

student_id   number(10),

student_name   varchar2(20) not null,

sex   char(2) not null,

birthday   date not null,

email   varchar2(20) unique,

classes_id   number(3) not null,

constraint   stu_pk_id primary key(student_id),

constraint   stu_fk_classes_id foreign key(classes_id) references t_classes(id),

constraint   stu_check_sex check(sex in('男','女'))

)

2.19.4、增删改表结构

当一个表已经包含数据,如果表结构需要改变,那么我们不能删除后,再创建表,这样数据会丢失,采用alter table来修改表结构

l  添加字段

例如:向t_student表中加入联系电话字段

alter table t_student add (telphone varchar2(20));

l  修改字段

例如:修改t_student中的student_name为varchar2(30)

alter table t_student add (telphone varchar2(20));

l  删除字段

例如:删除t_student中contact_tel

alter table t_student drop(telphone);

2.19.5、增删改约束

l  删除约束

将t_student表中的classes_id外键约束

alter table t_student drop constraint   stu_fk_classes_id;

l  添加约束

将t_student表中的classes_id加入外键约束

alter table  t_student   add constraint

stu_fk_classes_id  foreign key(classes_id)

references t_classes(id);

l  修改约束

修改t_student的student_name为null

alter table t_student modify(student_name   varchar(30) null);

2.19.6、删除表

Drop table 表名

如果存在外键关联,首先先删除子表,再删除父表

2.20、索引

索引的目的是加快查询速度,就像一本数据的目录一样。建立索引的原则:非常少的DML操作;经常出现在where语句中的字段

2.20.1、建立索引

l  对t_student中的birthday建立索引

create index idx_t_student_birthday on t_student(birthday);

2.20.2、删除索引

drop index IDX_T_STUDENT_BIRTHDAY;

2.21、视图

看如下示例:

select a.deptno, a.avg_sal, b.grade from

(select deptno, avg(sal) as   avg_sal from emp group by deptno) a,

salgrade b

where a.avg_sal between b.losal and b.hisal;

如果频繁使用以上查询语句,那么会带来维护的成本,那么需要使用到视图技术

2.21.1、创建视图

create view v_dept_avg_sal as

select a.deptno, a.avg_sal, b.grade from

(select deptno, avg(sal) as avg_sal from emp group by   deptno) a,

salgrade b

where a.avg_sal between b.losal and b.hisal;

执行以上语句创建视图,会出现没有权限的错误,因为scott用户没有授予创建视图的权利,如何查看当前用户的权限:

select * from session_privs;

切换用户

让scott以sysdba身份登录

Conn scott/tiger as sysdba

Sqlplus/nolog

Conn /as sysdba

开始授权,授予创建视图的权限

grant create view to scott;

前提是以sysdba权限登录,然后grant   resource, sysdba to scott;

再次切换到scott

conn scott/tiger

再次查看权限

select * from session_privs;

成功授予了创建视图的权限

开始创建视图

视图创建成功

视图的使用表一样,可以和表或和视图关联,但是视图不能进行增删改,只能进行查询。

视图最好不要频繁创建,当表结构发生改变将会影响到视图,视图的主要的作用就是查询的方便性

2.21.2、删除视图

Drop view 视图名称

2.22、序列:sequence

序列是Oracle专有的,主要来产生一个自增的数字序列,如:t_student表中的学号,我们就可以采用自增的方式,序列主要用在主键的生成上

还有一种经常使用的生成策略:identity,如:MySQL, Ms SQLServer

2.22.1、创建序列

create sequence seq_student_id    start with 1  increment by 1;

2.22.2、使用序列

向t_student表中插入数据

insert into t_student(student_id, student_name, sex,   birthday, classes_id)

values(SEQ_STUDENT_ID.nextval, 'zhangsan','男',to_date('2009-06-06',   'yyyy-mm-dd'), 111);

以上会看到,增加一个student,那么student_id会自增,如果出现错误,将会断号

2.22.3、删除序列

drop sequence SEQ_STUDENT_ID;

2.23、存储过程、触发器和游标

2.23.1、存储过程

存储过程最直接的理解:就是保存了批量的sql(select,insert,if for),以后可以通过一个名字把这些批量的sql执行,使用存储过程在大批量数据查询或计算时会带来高性能,存储过程存在确定,编写和调试复杂,不同数据库产品存储过程差异非常大,很难实现平滑一致

l  建立存储过程

create or replace procedure proc_test(in_var number,out_var out sys_refcursor)

as

begin

open   out_var for select * from new_emp where deptno=in_var;

end;

l  执行存储过程

2.23.2、触发器

触发器是特殊的存储过程,它与数据库的insert、update和delete相关联,如定义完成触发器之后,会在insert、update或delete语句执行前或执行后自动执行触发器中的内容

触发器示例,向new_emp表中加入数据,采用触发器自动再向t_log表里加入一条数据

l  首先建立t_log表

create table t_log (

log_id   number(10) primary key,

log_time   date

)

l  为建立t_log的主键建立sequence

create sequence seq_log_id start with 1 increment by 1;

l  建立触发器

create or replace trigger tri_test

after/before  insert/update/delete on new_emp

begin

insert into   t_log(log_id, log_time) values(seq_log_id.nextval, sysdate);

end;

l  向new_emp表中加入数据

insert into new_emp(empno, deptno) values(7777, 10);

在new_emp中多了一条数据empno为7777,在t_log中自动加入了一条数据,这就是触发器的作用。

2.24、游标

我们有时采用select会返回一个结果集,使用简单的select无法得到上一行,下一行,后5行,后10行,如果想做到这一点必须使用游标,游标是存储在数据库服务器上的一个数据库查询,它不是一条select语句,他是一个结果集,有了游标就可以根据需要滚动浏览数据了

下面通过一个示例,根据岗位加工资,如果是MANAGER增加20%的工资,如果是SALESMAN增加10%的工资,其他的增加5%的工资 ---delphi

create or replace procedure proc_sal

is

cursor c is

select   * from new_emp for update;

begin

for v_emp in c loop

if (v_emp.job =   'MANAGER') then

update new_emp set sal = sal + sal*0.2 where current of   c;

elsif   (v_emp.job = 'SALESMAN') then

update   new_emp set sal = sal + sal*0.1 where current of c;

else

update new_emp set sal = sal + sal*0.05 where current   of c;

end if;

end loop;

commit;//事物的提交

end;

执行存储过程

exec proc_sal;

2.25、常用的DBA操作

2.25.1、查询用户拥有的数据库对象

select object_name from user_objects;

2.25.2、查询约束信息

select constraint_name from user_constraints;

2.25.3、查询用户拥有的表

select * from tab;

select table_name from user_tables;

2.25.4、查询用户拥有的视图

select view_name from user_views;

2.25.5、查询用户拥有的触发器

select trigger_name from user_triggers;

2.25.6、查询用户拥有的序列

select sequence_name from user_sequences;

2.25.7、查询用户拥有的存储过程

select object_name from user_procedures;

2.25.8、查询用户拥有的索引

select index_name from user_indexes;

2.25.9、显示当前用户

show user;

2.25.10、切换用户

conn cms/cms

2.25.11、以某种角色来登录

conn scott/tiger as sysdba;

2.25.12、查看用户拥有的权限

select * from session_privs;

常用权限

CREATE SESSION

连接数据库

CREATE TABLE

创建表

CREATE VIEW

创建视图

CREATE SEQUENCE

创建序列

CREATE PROCEDURE

创建存储过程

CREATE TRIGGER

创建触发器

CREATE INDEXTYPE

创建索引

UNLIMITED TABLESPACE

对表空间的使用

Grant resource ,sysdba to scott

把以上所有资源都分配

2.25.13给用户加锁

alter user scott account lock;

2.25.14给用户解

alter user scott account unlock;

2.25.15、改用户的密码

alter user scott identified by   tiger;

2.25.16建立用户

create user test1(username) identified by test1(password);

2.25.17删除用户

可以级联删除

drop user test1 cascade;

2.25.18、给用户授权

grant create session,create table to test1;

2.25.19、授予表空间users给用户

alter user test1 default tablespace users;

2.25.20、给用户 授权表空间

grant UNLIMITED TABLESPACE to test1;

2.25.21一个完整的过程,从创建用户、创建表空间、授权、建表

l  创建用户

create user test123 identified by test123;

l  创建表空间

create tablespace data001 datafile 'd:\data001.dbf' size 100m;

l  分配表空间给用户

alter user test123 default tablespace data001;

l  给用户授权

grant create session,create table, UNLIMITED TABLESPACE to test123;

l  以test123登录

conn test123/test123;

l  创建表。。。。

2.25.22、导入和导出命令imp(import)、exp(export)

EXPDAT.DMP

数据库的格式:dmp文件:备份数据库

2.26、数据库设计的三范式

2.26.1、第一范式

数据库表中不能出现重复记录,每个字段是原子性的不能再分

不符合第一范式的示例

学生编号

学生姓名

联系方式

1001

张三

zs@gmail.com,1369999999

1002

李四

ls@gmail.com,13999888777

1001

王五

ww@163.net, 13455566677

存在问题:

n  最后一条记录和第一条重复(不唯一,没有主键)

n  联系方式字段可以再分,不是原子性的

学生编号(pk

学生姓名

email

联系电话

1001

张三

zs@gmail.com

1369999999

1002

李四

ls@gmail.com

13999888777

1003

王五

ww@163.net

13455566677

关于第一范式,每一行必须唯一,也就是每个表必须有主键,这是我们数据库设计的最基本要求,主要通常采用数值型或定长字符串表示,关于列不可再分,应该根据具体的情况来决定。如联系方式,为了开发上的便利行可能就采用一个字段了。

2.26.2、第二范式

第二范式是建立在第一范式基础上的,另外要求所有非主键字段完全依赖主键,不能产生部分依赖

示例:

学生编号

学生姓名

教师编号

教师姓名

1001

张三

001

王老师

1002

李四

002

赵老师

1003

王五

001

王老师

1001

张三

002

赵老师

确定主键:

学生编号(PK)

教师编号(PK)

学生姓名

教师姓名

1001

001

张三

王老师

1002

002

李四

赵老师

1003

001

王五

王老师

1001

002

张三

赵老师

以上虽然确定了主键,但此表会出现大量的冗余,主要涉及到的冗余字段为“学生姓名”和“教师姓名”,出现冗余的原因在于,学生姓名部分依赖了主键的一个字段学生编号,而没有依赖教师编号,而教师姓名部门依赖了主键的一个字段教师编号,这就是第二范式部分依赖。

解决方案如下:

学生信息表

学生编号(PK)

学生姓名

1001

张三

1002

李四

1003

王五

教师信息表

教师编号(PK)

教师姓名

001

王老师

002

赵老师

教师和学生的关系表

学生编号(PK)

教师编号(PK)

1001

001

1002

002

1003

001

1001

002

如果一个表是单一主键,那么它就复合第二范式,部分依赖和主键有关系

2.26.3、第三范式

建立在第二范式基础上的,非主键字段不能传递依赖于主键字段。

学生编号(PK)

学生姓名

班级编号

班级名称

1001

张三

01

一年一班

1002

李四

02

一年二班

1003

王五

03

一年三班

从上表可以看出,班级名称字段存在冗余,因为班级名称字段没有直接依赖于主键,班级名称字段依赖于班级编号,班级编号依赖于学生编号,那么这就是传递依赖,解决的办法是将冗余字段单独拿出来建立表,如:

学生信息表

学生编号(PK)

学生姓名

班级编号

1001

张三

01

1002

李四

02

1003

王五

03

班级信息表

班级编号

班级名称

01

一年一班

02

一年二班

03

一年三班

2.26.3、三范式总结

第一范式:有主键,具有原子性,字段不可分割

第二范式:完全依赖,没有部分依赖

第三范式:没有传递依赖

数据库设计尽量遵循三范式,但是还是根据实际情况进行取舍,有时可能会那冗余换速度,最终用目的要满足客户需求。

3、练习

3.1、取得每个部门最高薪水的人员名称

1、取得每个部门的最高薪水

2、然后把结果当成一张表,再用emp和结果做关联

select a.ename, a.sal, a.deptno from emp a join

(select deptno, max(sal) max_sal from emp group by   deptno) b

on (a.deptno=b.deptno   and a.sal=b.max_sal)

3.2、哪些人的薪水在部门的平均薪水之上

1、首先取得每个部门的平均薪水

2、然后把结果集当成一张表,再用emp和这张表做连接

select a.ename, a.sal from emp a join

(select deptno, avg(sal) avg_sal from emp group by   deptno) b

on (a.deptno=b.deptno and a.sal > b.avg_sal);

3.3、取得部门中(所有人的)平均的薪水等级,如下:

1、每个人的薪水等级

2、按部门分组取平均等级

select deptno, avg(grade) from

(select a.ename, a.deptno, b.grade from emp a join

salgrade b on (a.sal between b.losal and b.hisal))

group by deptno;

3.4、不准用组函数(Max),取得最高薪水(给出两种解决方案)

第一种解决办法:

1、先把所有的薪水按降序排列

select sal from

(select sal from emp order by sal desc)

where rownum <=1;

第二种解决办法:

1、 将emp作为两个表,进行比较,得出最大值以外的所有值

2、 然后采用not in

select sal from emp where sal not in(

select   distinct a.sal from emp a join emp b on (a.sal < b.sal)

)

3.5、取得平均薪水最高的部门的部门编号(至少给出两种解决方案)

第一种解决办法:

1、 取得每个部门的平均薪水

2、 再取每个部门平均薪水的最大值

3、 然后平均薪水和平均薪水的最大值比较,得出部门编号

select deptno from

(select deptno, avg(sal) avg_sal from emp group by   deptno)

where avg_sal =(

select max(avg_sal) from

(select deptno, avg(sal) avg_sal from emp group by   deptno)

)

 

第二种解决办法:

1、 取得平均薪水的最大值

2、 然后平均薪水和平均薪水的最大值比较,得出部门编号

select deptno from

(select deptno, avg(sal) avg_sal from emp group by   deptno)

where avg_sal = (

select max(avg(sal)) from emp group by deptno

)

 

第三种解决办法:

1、 先取得部门的平均薪水

a)       select deptno, avg(sal) from emp group by deptno

2、 取得最高薪水

a)       select max(avg(sal)) from emp group by deptno

3、 最后采用having子句做等值比较

select deptno, avg(sal) from emp group by deptno

having avg(sal) = (select max(avg(sal)) from emp group   by deptno)

3.6、取得平均薪水最高的部门的部门名称

1、 取得部门平均最高薪水

a)       select max(avg(sal)) from emp group by deptno)

2、 得到部门编号列表

a)       select deptno from emp group by deptno

3、 采用having子句比较取得平均最高薪水的部门编号

(select deptno

from   emp group by deptno

having   avg(sal) = (select max(avg(sal)) from emp group by deptno)

4、 得到部门名称

select dname

from dept

where deptno in

(select   deptno

from   emp group by deptno

having   avg(sal) = (select max(avg(sal)) from emp group by deptno))

3.7、求平均薪水的等级最低的部门的部门名称

1、 取得部门平均薪水等级

select deptno, avg_sal, grade from

(select   deptno, avg(sal) avg_sal from emp group by deptno) join

salgrade   on avg_sal between losal and hisal)

2、 取得最低等级

select min(grade) from

(select   deptno, avg_sal, grade from

(select   deptno, avg(sal) avg_sal from emp group by deptno) join

salgrade   on avg_sal between losal and hisal)

3、 在薪水等级集合中,取得最小薪水等级记录,与步骤二对比

4、 然后取得部门代码

5、 最后取得部门名称

select dname from dept where deptno in

(

select   deptno from

((select   deptno, avg_sal, grade from

(select   deptno, avg(sal) avg_sal from emp group by deptno) join

salgrade   on avg_sal between losal and hisal)

)where grade = (select   min(grade) from

(select   deptno, avg_sal, grade from

(select   deptno, avg(sal) avg_sal from emp group by deptno) join

salgrade   on avg_sal between losal and hisal))

)

3.8、取得比普通员工的最高薪水还要高的经理人姓名

1、 先取得经理人

n  select distinct mgr from emp where mgr is not null

2、 取得普通员工的坐高薪水

n  (select max(sal) from emp where empno not in (select distinct mgr from emp where mgr is not null))

3、 取得经理人的薪水,与普通员工最高薪水对比

select ename, sal from emp

where empno in (select distinct mgr from emp where mgr   is not null)

and sal >普通员工的最高薪水

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))

3.9、取得薪水最高的前五名员工

select rownum, ename,sal from

(select ename, sal from emp order by sal desc)

where rownum<=5;

3.10、取得薪水最高的第六到第十名员工

select ename, sal from

(select rownum r, ename,sal from

(select ename,sal from emp order by sal desc)

where rownum<=10)

where r>=6;

3.11、取得最后入职的5名员工

select ename,to_char(hiredate,'yyyy-mm-dd') from

(select ename, hiredate from emp order by hiredate   desc)

where rownum <=5;

3.12、取得每个薪水等级有多少员工

1、取得每个员工的薪水等级

2、更具薪水等级分组,取count

select grade, count(*) from

(select   ename,sal,grade from emp join salgrade on sal between losal and hisal)

group by grade

3.13、面试题

有3个表S,C,SC

S(SNO,SNAME)代表(学号,姓名)

C(CNO,CNAME,CTEACHER)代表(课号,课名,教师)

SC(SNO,CNO,SCGRADE)代表(学号,课号,成绩)

问题:

1,找出没选过“黎明”老师的所有学生姓名。

2,列出2门以上(含2门)不及格学生姓名及平均成绩。

3,即学过1号课程又学过2号课所有学生的姓名。

请用标准SQL语言写出答案,方言也行(请说明是使用什么方言)。

-----------------------------------------------------------------------------

CREATE TABLE SC

(

SNO      VARCHAR2(200 BYTE),

CNO      VARCHAR2(200 BYTE),

SCGRADE  VARCHAR2(200 BYTE)

);

CREATE TABLE S

(

SNO    VARCHAR2(200 BYTE),

SNAME  VARCHAR2(200 BYTE)

);

CREATE TABLE C

(

CNO       VARCHAR2(200 BYTE),

CNAME     VARCHAR2(200 BYTE),

CTEACHER  VARCHAR2(200 BYTE)

);

INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '1', '语文', '张');

INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '2', '政治', '王');

INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '3', '英语', '李');

INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '4', '数学', '赵');

INSERT INTO C ( CNO, CNAME, CTEACHER ) VALUES ( '5', '物理', '黎明');

commit;

INSERT INTO S ( SNO, SNAME ) VALUES ( '1', '学生1');

INSERT INTO S ( SNO, SNAME ) VALUES ( '2', '学生2');

INSERT INTO S ( SNO, SNAME ) VALUES ( '3', '学生3');

INSERT INTO S ( SNO, SNAME ) VALUES ( '4', '学生4');

commit;

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '1', '40');

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '2', '30');

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '3', '20');

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '4', '80');

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '1', '5', '60');

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '1', '60');

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '2', '60');

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '3', '60');

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '4', '60');

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '2', '5', '40');

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '3', '1', '60');

INSERT INTO SC ( SNO, CNO, SCGRADE ) VALUES ( '3', '3', '80');

commit;

问题1.找出没选过“黎明”老师的所有学生姓名。

第一步:求黎明老师教的所有课的课号

select distinct cno from c where cteacher='黎明'

第二步:选了黎明老师的所有学生的编号

select sno from sc where cno in (

第一步的结果

)

第三步:没有选黎明老师的所有学生的姓名

select sname from s where sno not in (

第二步的结果

)

即:

select sname from s where sno not in (

select sno   from sc where cno in (

select   distinct cno from c where cteacher='黎明'

)

)

问题2:列出2门以上(含2门)不及格学生姓名及平均成绩。

第一步:2门以上不及格的学生的学号

select sno from sc where scgrade < 60 group by sno having count(*) >= 2

第二步:每个学生平均分

select sno, avg(scgrade) as avg_grade from sc group by sno

第三步:第一步中得到的学号对应的学生姓名以及平均分

select s.sname ,avg_grade from s

join

第一步的结果

on s.sno = t.sno

join

第二步的结果

on s.sno = t1.sno

即:

select s.sname ,avg_grade from s

join

(select sno, count(*) from sc where scgrade < 60 group by sno having count(*) >= 2)t

on s.sno = t.sno

join

(select sno, avg(scgrade) as avg_grade from sc group by sno )t1

on s.sno = t1.sno

问题3:即学过1号课程又学过2号课所有学生的姓名。

第一步:学过1号课程的学号

select sno from sc where cno = 1

第二步:学过2号课程的学号

select sno from sc where cno = 2

第三步:即学过1号课程又学过2号课的学号

select sno from sc where cno =1 and sno in (select sno from sc where cno = 2)

第四步:得到姓名

select sname from s where sno in (

select sno from sc where cno = 1 and sno in (select sno from sc where cno = 2)

)

或者:

select sname from s where

sno in (select sno from sc where cno = 1)

and

sno in (select sno from sc where cno = 2)

PL/SQL工具的使用

  1. 连接方式:

2.打开左侧的下拉框:选择:My objects

  1. 右键的功能
  1. 导出:

文件的格式:.dmp和.sql

Dmp;

导出.sql文件

导出.dmp文件

导入:@ 文件路径

例如:@c:\cms.sql :导入sql中的数据

5.

SQL WINDOW菜单,主要是写sql语句或执行sql语句

6.导入:

Cd  oracle的bin目录下:例如我的oracle安装路径:F:\oracle\product\10.1.0\db_1\BIN

Cd F:\oracle\product\10.1.0\db_1\BIN

导入dmp文件

imp cms/cms file=c:\cms.dmp  full=y;

如果上面不可用,可用下面方式from表示来自哪个用户,to是要到哪个用户。

imp cms/cms file=c:\cms.dmp  from  scott  to  cms ;

Client

Server

导出dmp文件:

exp cms/cms file=d:\cms.dmp ;

7.本机oracle客户端如何连接服务器?

如果连不上的问题:关闭代理软件

1)打开oracle------------------》configuration and Migration Tools---------》

--------------》NET manager

修改服务命名标签中的:

主机名:写服务器的ip地址

监听程序:主机:写ip地址

点击文件中的save。

然后,PL/SQL工具来连接服务器数据库。

如果连接不上,重启服务器

1.打开方式如下:在运行中打入以下命令

services.msc

然后重启:oracle的service和LISTENER

2.修改一下服务名为服务器的sid名即可。

任务:

  1. 创建用户sinojava密码为:sinojava
  2. 授权给sinojava权限
  3. 拷贝scott用户中的数据表emp到sinojava用户下。
  4. 在sinojava用户下面,把表emp复制一份并命名为:new_emp
  5. 往new_emp表中插入1条数据。
  6. 导出此用户下的数据库及表的sql文件

SQLServer2005

Sever name:ip地址

Login:用户名

Pawword:密码

选择语句:shift+home或end

快捷键:F5执行sql键

创建数据库:create database cms;//create database 数据库名

打开数据库:use cms;或可用的所有的数据库下拉框选择

创建表

create table t_user (

id int not null primary key,

name varchar(20) not null,

sex char(2) not null,

mobile varchar(11)

);

Data types:

Int

Bigint:长整型

Char

Datetime

Decimal:十进制

Float

Money

Numeric

Samllint:短整型

Varchar:字符型的都可以使用

插入表:

insert into t_user

values(1,'tom','男','13439485642');

(1 row(s) affected)

删除表

delete from t_user where id=1;

修改表

update t_user set name='lucy' where id =2;

查询表

select * from t_user;

select id,name,sex,mobile from t_user;

配置sqlserver2005 服务

1,            开始>>程序>>Microsoft SQLServer2005 >>配置工具>>SQL Server Configurationo Manager

1..1启动图上服务

1.2 启动图上前三项

1.3 启动图上前三项

最新文章

  1. MVP初探
  2. AngularJS开发之_指令
  3. POJ-2991 Crane(区间更新+向量旋转)
  4. CSS3 必须要知道的10 个顶级命令
  5. c# 可以设置透明度的 Panel 组件
  6. animateWithDuration 动画的速度选择
  7. 【LeetCode】9 &amp; 234 &amp; 206 - Palindrome Number &amp; Palindrome Linked List &amp; Reverse Linked List
  8. BackTrack5 (BT5)无线password破解教程之WPA/WPA2-PSK型无线password破解
  9. 【mysql的编程专题⑤】自定义函数
  10. 转:Java程序员最常用的8个Java日志框架
  11. 异常学习笔记+打包+doc该软件包编译
  12. vmare虚拟化解决方案
  13. easywechat之微信支付--在thinkPHP5中的使用
  14. 聊聊pytorch中的DataLoader
  15. Java运算符和引用数据类型(Scanner、Random)
  16. 如何在Python中使用ZeroMQ和Docker构建微服务架构
  17. VIM编辑器常用命令(转)
  18. [EffectiveC++]item04:Make sure the objects are initialized before they&#39;re used
  19. 47、求1+2+3+...+n
  20. python3----函数(sort和sorted)

热门文章

  1. 分析Linux内核的启动过程
  2. HTTP要点概述:六,HTTP报文
  3. CSU 1806 Toll 自适应simpson积分+最短路
  4. HTTP请求错误码大全(转)
  5. Eclipse 配置 Python 环境
  6. CSS3 核心知识面试题
  7. JavaScript--DOM节点属性
  8. KMP POJ 1961 Period
  9. The Chosen One
  10. jquery.autocomplete.js用法及示例,小白进