您的位置:首页 > 运维架构

维护数据的完整性(16)

2015-07-30 11:12 260 查看
介绍

数据的完整性用于确保数据库遵从一定的商业和逻辑规则。在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之间就会提示出错。

商店售货系统表设计案例(1)

现有一个商店的数据库,记录客户及其购物情况,由下面三个表组成:

商品goods(商品号goodsld,商品名goodsname,单价unitprice,商品类别category,供应商provider);

客户customer(客户号customerld,姓名name,住址address,电邮email,性别sex,身份证cardid);

购买purchase(客户号customerid,商品号goodsld,购买数量nums);

请用sql语言完成下列功能:

1.建表,在定义中要求声明:

(1)每个表的主外键;

(2)客户的姓名不能为空值;

(3)单价必须大于0,购买数量必须在1到30之间;

(4)电邮不能够重复;

(5)客户的性别必须是男或者女,默认是男

SQL> create table goods(goodsid char(8) primary key,

  2  goodsname varchar2(30),

  3  unitprice number(10,2) check(unitprice > 0),

  4  category varchar2(8),

  5  provider varchar2(30));

表已创建。

SQL>

SQL> create table customer(customeril char(8) primarykey,

  2  name varchar2(50) not null,

  3  address varchar2(50),

  4  email varchar2(50) unique,

  5  sex char(2) default '男' check(sexin('男','女')),

  6  carid char(10));

表已创建。

SQL>

商店售货系统表设计案例(2)

现有一个商店的数据库,记录客户及其购物情况,由下面三个表组成:

商品goods(商品号goodsld,商品名goodsname,单价unitprice,商品类别category,供应商provider);

客户customer(客户号customerld,姓名name,住址address,电邮email,性别sex,身份证cardid);

购买purchase(客户号customerid,商品号goodsld,购买数量nums);

请用sql语言完成下列功能:

1.建表,在定义中要求声明:

(1)每个表的主外键;

(2)客户的姓名不能为空值;----名也不能为空增加商品

SQL> alter table goods modify goodsname not null;

(3)单价必须大于0,购买数量必须在1到30之间;

(4)电邮不能够重复;---增加身份证也不能重复

SQL> alter table customer add constraint carduniqueunique(carid);

(5)客户的性别必须是男或者女,默认是男

(6)增加客户的住址只能是‘海淀’、‘朝阳’、‘东城’、‘西城’、‘通州’、崇文

SQL>alter table customer add constraint addresscheckcheck (address in ('东城','西城'));

删除约束

当不再需要某个约束时,可以删除

alter table 表名 drop constraint 约束名称;

在删除主键约束的时候,可能有错误

Alter table 表名 drop primary key;

这是因为如果在两张表存在主从关系,那么在删除主表的主键约束时,必须带上cascade选项 如像:

Alter table 表名 drop primary key cascade;

显示约束信息                                                                                

1.  显示约束信息

  通过查询数据字典视图user_constraints,可以显示当前用户所有的约束的信息

SQL>select constraint_name,constraint_type,status,validated fromuser_constraints where table_name='GOODS'

2.显示约束列

通过查询数据字典视图user_cons_columns,可以显示约束所对应的表的信息

SQL> select column_name,position from user_cons_columns whereconstraint_name='SYS_C005504';

SQL> select column_name,position from user_cons_columns whereconstraint_name='约束名';

列级定义

列级定义是在定义列的同时定义约束

如在department表定义主键约束

create table department4(dept_id number(2) constraint pk_department primary key,name varchar2(12),locvarchar2(12));

表级定义

表级定义是指在定义了所有列后,再定义约束。这里需要注意:

not null约束只能在列级定义

以在建立employee2表时定义主键约束和外键约束为例:

create table employee2(emp_id number(4),name varchar2(15),dept_id number(2),constraintpk_employee primary key (emp_id),constraint fk_department foreign key (dept_id) references department4(dept_id);

角色

角色就是相关权限的命令集合,使用角色的主要目的就是为了简化权限的管理,假定有用户a,b,c为了让他们都拥有权限

1.连接数据库

2.在scott.emp表上select,insert,update

如采用直接授权操作,则需要进行12次授权。

我们如果采用角色就可以简化:

首先将create session,select on scott.emp,insert on scoyy.emp,update on scott.emp授予角色,让后将该角色授予、a,b,c用户,这样就可以三次授权搞定。

角色分为预定义和自定义角色两类

预定于角色

预定义角色是指oracle所提供的角色,每种角色都用于执行一些特定的管理任务,下面我们介绍常用的预定义角色connect,resource,dba

1.connect角色

connect角色具有一般应用开发人员需要的大部分权限,当建立了一个用户后,多数情况下,只要给用户授予connect和resource角色就够了,那么connect角色具有哪些系统权限?

2.resource角色

resource角色具有应用开发人员所需要的其他权限,比如建立存储过程、触发器等。这里需要注意的是resource角色隐含了unlimited tablespace系统权限。

3.dba权限

dba角色具有所有的系统权限,及with admin option选项,默认的dba用户为sys和system他们可以将任何系统权限授予其他用户。但是要注意的是dba角色不具备sysdba和sysoper的特权(启动和关闭数据库)

自定义角色

顾名思义就是自己定义的角色,根据自己需要来定义,一般是dba来建立,如果用别的用户来建立,则需要具有create role的系统权限,在建立角色时可以指定验证方式(不验证,数据库验证等)

1.建立角色(不验证)

如果角色是公用的角色,可以采用不验证的方式建立角色

create role角色名 not identified;

2.建立角色(数据库验证)

采用这样的方式时,角色名、口令存放在数据库中。当激活该角色时、必须提供口令。在建立这种角色时,需要为其提供口令

create role 角色名 identified by shen

角色授权

1.   分配角色给某个用户

2.      一般分配角色是由dba来完成的,如果需要以其他用户身份分配角色,则要求用户必须具有grant  any role的系统权限

SQL>grant 角色名 to lin with admin option 

SQL> grant ling to lin;把ling角色授权给lin用户。

加上with admin option选项lin用户可以把system给他的角色分配给其他用户。

 

删除角色

使用drop role,一般dba来执行,如用其他用户则要求该用具有drop any role系统权限

SQL> drop role ling;

 

角色已删除。(删除角色后,用户就不能登录)

 

显示角色信息

1.      显示所有角色

SQL> select * from dba_roles;

2.      显示角色具有的系统权限

SQL> select privilege,admin_option from role_sys_privswhere role='CONNECT';

3.      显示角色具有的对象权限

通过查询数据字典视图dba_tabl_privs可以查看角色具有的对象权限或是列的权限。

4.      显示用户的角色,及默认角色

当用户的身份连接到数据库时,oracle会自动的激活默认的角色,通过查询数据字典视图dba_role_privs可以显示某个用户具有的所有角色及当前默认的角色

SQL> select granted_role,default_role fromdba_role_privs where grantee='LIN';

 

 

 

 

PL/SQL(18)

1.      创建一个简单的表

SQL> create table mtest(name varchar2(30),passwdvarchar2(30));

2.      创建过程

SQL>create or replace procedure sp_pro1 is

  2 begin

  3 insert into mtest values('沈奇阳','sqy');

  4  end;

  5  /

 

过程已创建。

      Replace:表示如已经有sp_pro1,就替换

 

      如何查看错误信息:

      SQL> show error;

 

      如何调用该过程

1.  Exec 过程名(参数值1,参数值2…)

SQL>exec sp_pro1;

 

PL/SQL 过程已成功完成。

2.  call 过程名(参数值1,参数值2…)

 

 

编写规范

1注释

单行注释—

Select * from emp;--取得员工信息

多行注释

/*….*/来划分

3.      标识符号的命名规范

(1)      当定义变量时,建议使用v_作为前缀  v_sal

(2)      当定义常量时,建议用c_作为前缀 c_rate

(3)      当定义游标时,建议用_cursor作为后缀 emp_cursor;

(4)      当定义例外时,建议用e_作为前缀e_error

 

块(block)是PL/SQL的基本单元,编写pl/sql程序实际上就是编写pl/sql块。要完成相对应简单的应用功能,可能只需要编写一个pl/sql块;但是如果要实现复杂的功能,可能需要在一个pl/sql块中嵌套其他的pl/sql块。

 

块结构示意图

Pl/sql块由三个部分构成:定义部分、执行部分、例外部分。

如下所示:

Declear

/*定义部分----定义常量、变量、游标、例外、复杂数据类型*/

Begin

/*执行部分----要执行的pl/sql语句和sql语句*/

Exception

/*例外处理部分----处理运行的各种错误*/

End;

 

 

特别说明:

定义部分是从declare开始的,该部分是可选的

执行部分是从begin开始的,该部分是必须的

例外部分是从exception开始的,该部分是可选的

 

实例1-只包括执行部分的pl/sql块

Set serverout on—打开输出选项

 

 

 

SQL>begin
  2   dbms_output.put_line('hello');
  3  end;
  4  /
 hello
 PL/SQL procedure successfully completed
 
相关说明:

Dbms_output是oracle所提供的包(类似java的开发包),该包包含一些过程,put_line就是dbms_output包的一个过程。dbms_output.put_line是输出。

 

 

实例2—包含定义部分和执行部分的pl/sql块接收

SQL>declare
  2   v_ename varchar2(5);--定义带字符串变量
  3   v_sal number(7,2);
  4 begin--执行部分
  5   select ename,sal into v_ename,v_sal from emp where empno=&no;--在控制台显示用户名
  6   dbms_output.put_line('雇员名:'||v_ename||' 工资:'||v_sal);
  7  end;
  8  /
 雇员名:sqy 工资:6000
 PL/SQL procedure successfully completed
 SQL>
相关说明:

& 表示要接收从控制台输入的变量

/*其中ename into v_ename是指把查出来的ename的值赋值给v_ename*/
实例3—包含定义部分、执行部分和例外处理部分

为了避免pl/sql程序的运行错误,提高pl/sql的健壮性,应该对可能的错误进行处理,这个很有必要:

1.  比如在实例2中,如果输入了不存在的雇员号,应当做例外处理。

2.  有时出现异常,希望用另外的逻辑处理,我们如何完成1的要求

相关说明:oracle事先预定义了一些例外,no_data_found就是找不到数据的例外。

SQL>declare
  2   v_ename varchar2(5);--定义带字符串变量
  3   v_sal number(7,2);
  4 begin--执行部分
  5   select ename,sal into v_ename,v_sal from emp where empno=&no;--在控制台显示用户名
  6   dbms_output.put_line('雇员名:'||v_ename||' 工资:'||v_sal);
  7  --异常处理
  8 exception
  9   when no_data_found then
 10     dbms_output.put_line('你的输入编号有误');
 11  end;
 12  /
你的输入编号有误
PL/SQLprocedure successfully completed
 SQL>
 
 
过程
过程用于执行特定的操作,当建立过程时,即可以这些hidin输入的参数(in),也可以指定输出参数(out)。通过在过程中使用输入参数,可以将数据传递到执行部分;通过使用输出参数,可以将执行部分的数据传递到应用环境。在sqlplus中可以使用create procedure命令来建立过程。
实例如下:
1请考虑编写一个过程,可以输入雇员名,新工资,可修改雇员的工资
2.如何调用过程有两种方法
3.如何在java程序中调用一个存储过程
创建过程名为sp_pro3
SQL>create procedure sp_pro3(spname varchar2,newsal number) is
  2 begin--执行部分,根据用户去 修改工资
  3 upd
bcac
ate emp set sal=newsal where ename=spname;
  4  end;
  5  /
 Procedure created
 SQL>
调用过程:
SQL>exec sp_pro3('scott',5678);
PL/SQLprocedure successfully completed
SQL>

 

 
 
 
SQL>declare
  2 c_tar_rate number(3,2):=0.03;
  3 v_ename varchar2(5);
  4 v_sal number(7,2);
  5 v_tax_sal number(7,2);
  6 begin
  7 select ename,sal into v_ename,v_sal from emp where empno=&no;
  8 v_tax_sal:=v_sal*c_tar_rate;
  9 dbms_output.put_line('姓名是:'||v_ename||'工资:'||v_sal||'交税'||v_tax_sal);
 10  end;
 11  /
姓名是:SCOTT工资:4678交税140.34
PL/SQLprocedure successfully completed
SQL>
 
 

 

 
 
 
SQL>declare
  2  typeemp_record_type is record(name emp.ename%type,salary emp.sal%type,titleemp.job%type);
  3 sp_record emp_record_type;
  4  begin
  5 select ename,sal,job into sp_record
  6  fromemp where empno=7788;
  7 dbms_output.put_line('员工名'||sp_record.name);
  8  end;
  9  /
员工名SCOTT
PL/SQLprocedure successfully completed

SQL>

SQL>declare
  2  typesp_table_type is table of emp.ename%type index by binary_integer;
  3 sp_table sp_table_type;
  4 begin
  5 select ename into sp_table(0) from emp where empno=7788;
  6 dbms_output.put_line('员工名:'||sp_table(0));
  7  end;
  8  /
员工名:SCOTT
PL/SQLprocedure successfully completed
SQL>

 

declare
type sp_emp_cursor
is ref cursor;
test_cursorsp_emp_cursor;
v_enameemp.ename%type;
v_salemp.sal%type;
begin
open test_cursor
for select ename,sal
from emp;
loop
fetch test_cursor
into v_ename,v_sal;
exit when test_cursor%notfound;
dbms_output.put_line('工资:'||v_sal||'名字:'||v_ename
);
end loop;
close test_cursor;

end;

编写一个PL/SQL程序块,对名字以"A"或"S"开始的所有雇员按他们的基本薪水的10%加薪。
declare
cursor c1
is select *
from emp where ename
like 'A%'
or ename like 'S%';
c1recc1%rowtype;
begin
for c1rec
in c1 loop
update emp
set sal=sal*1.1
where ename=c1rec.ename;
end loop;

end;

 
编写一PL/SQL,对所有的"销售员"(SALESMAN)增加佣金500.
 
declare
cursor c1
is select *
from emp where job='SALESMAN';
c1recc1%rowtype;
begin
for c1rec
in c1 loop
update emp
set sal=sal+500
where ename=c1rec.ename;
end loop;

end;

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: