Oracle 模式对象

chap 3 模式对象

数据库约束有五种:

  •      主键约束(PRIMARY KEY)
  •      唯一性约束(UNIQUE)
  •      非空约束(NOT NULL)
  •      外键约束(FOREIGN KEY)
  •      检查约束(CHECK)

constraint   xskc_p1 PRIMARY KEY(XH, KCH)         约束constraint

把已经存在的表放入表空间中

alter table xs  move tablespace users!!!!

foreign key (cpno) references course(cno)

【例1创建XS表中计算机专业学生的记录备份。

CREATE TABLE XS_JSJ   AS SELECT *     FROM SCOTT.XS_KC

 WHERE CJ>100

【例2】(再次重复!!)(1) XS中增加2列:JXJ(奖学金等级)DJSM(奖学金等级说明)

ALTER TABLE SCOTT.XS  ADD ( JXJ NUMBER(1), DJSM VARCHAR2(40) DEFAULT  '奖金1000');

  (2) 在表XS中修改名为DJSM的列的默认值。

 ALTER TABLE SCOTT.XS   MODIFY ( DJSM DEFAULT '奖金800' );

  (3) 在表XS中删除名为JXJDJSM的列。

  ALTER TABLE SCOTT.XS    DROP COLUMN JXJ;

  ALTER TABLE SCOTT.XS     DROP COLUMN DJSM;

按照约束的用途可以将表的完整性约束(constraint)分为5

1.NOT NULL   非空约束。指定一列不允许存储空值。这实际就是一种强制的CHECK约束 

 2.PRIMARY    KEY  主键约束。指定表的主键

 3. UNIQUE   唯一约束。指定一列或一组列只能存储唯一的值 

 4. CHECK   检查约束。指定一列或一组列的值必须满足某种条件 

5. FOREIGN   KEY    指定表的外键。外键引用另外一个表中的一列,在自引用的情况中,则引用本表中的一列 

例1:  向XSCJ数据库的表XS中插入如下的一行:

061101  王林  计算机  男  19870201  50

INSERT INTO XS(XH,XM,ZYM,XB,CSSJ,ZXF)     

 VALUES('061101','王林', '计算机','',

TO_DATE('19860210','YYYYMMDD'),50);

例2:select TO_DATE('19860210','YYYYMMDD') from dual

TO_DATE(字符串, '格式’)

作用:将字符转换为日期类型 

!!!  SQL> create table xs1 as select * from xs;

   SQL> truncate table xs1;

这个是重点了啊

  1. list(列表) 分区     列表分区表是基于特定值对表进行分区,其分区列的值为非数值型或日期类型,并且分区列的取值范围较少,所以一般为字符型, partition by list子句,列表值相同的行将被存储到同一分区中)

 

create table part_book1

     (  bid number(4),

        bookname VARCHAR2(20),

        bookpress VARCHAR2(30),

      booktime date)

partition by list(bookpress)

  (partition part1 values('清华大学出版社') tablespace system,

  partition part2 values('教育出版社') tablespace users);

alter table part_book1

add partition part3 values(default) tablespace system;

 

 

create table part_book

 (  bid number(4),

     bookname  VARCHAR2(20),

     bookpress  VARCHAR2(30),

     booktime date)

      partition by range(booktime)

        (partition part1 values less than(to_date('20100101','yyyymmdd'))  tablespace system,

          partition part2 values less than (to_date('20120101','yyyymmdd'))   tablespace users,

          partition part3 values less than (MAXVALUE)  tablespace users

        );

insert into part_book values(1,'oracle','清华大学出版社',to_date('20110102','yyyymmdd'));

insert into part_book values(2,'oracle','清华大学出版社',to_date('20090101','yyyymmdd'));

分区表的切割举例:将part3分区切割为两个新的分区,名字为part3、part4,分区的的依据值为20140101.

alter table  part_book4

split partition part3 at (to_date('20140101','yyyymmdd'))

into(partition part3,partition part4)

删除分区

举例:alter table  part_book  drop partition part3;

【例1】为KC表的课程名列创建索引。

            CREATE INDEX kc_name_idx

                     ON KC(KCM)

                     TABLESPACE users;

【例1.1】在xs表的xm列上创建基于LOWER函数的索引,如下:

CREATE INDEX name_lower_index

    ON xs(LOWER(xm))

    TABLESPACE users;

【例2】创建同义词。

    (1) 为XSCJ数据库的XS_KC表创建公用同义词XS_KC。

    CREATE PUBLIC SYNONYM XS_KC

     FOR SYSTEM.XS_KC;

【例3】删除公用同义词CS_XS。

DROP PUBLIC SYNONYM CS_XS;

【例4】创建一个降序序列。

Create sequence  stu_sequence

    start with 5000

         increment by   -2

            maxvalue  5000

                minvalue  1

                     nocycle;

Insert into student values(stu_sequence.nextval, '李明');

例如,要删除S_TEST序列,可使用如下语句:

DROP sequence student_sequence;

引用序列是通过伪列nextval完成的,它用的是序列的 下一个值,若引用当前值,则用伪列currval;

重点!!!!!

(PLSQL!!)

要求:向学生表中添加 记录,值为’007’ ‘Jame’ ‘计算机’ 45,并说明是否成功

DECLARE

      v_xm varchar2(8):='Jame';

    v_zym varchar2(10):='计算机';

    v_zxf number(2):=45;    /*定义变量类型*/

  BEGIN

 INSERT INTO XS(XH,XM,ZYM,ZXF)        VALUES('007',v_xm,v_zym,v_zxf);

 IF SQL%FOUND THEN

       DBMS_OUTPUT.PUT_LINE('操作成功');

ELSE

      DBMS_OUTPUT.PUT_LINE('没有插入该人');

 END IF;

END;

2  要求:针对scott.emp表,计算7788号雇员的应交税金情况,薪金>=3000,应缴税金为薪金的0.08,薪金在1500和3000之间,应缴薪金的0.06,其它应缴0.04.

  declare

   v_sal  scott.emp.sal%type;

   v_tax   scott.emp.sal%type;

begin

   select sal into v_sal  from  scott.emp  where empno=7788;

   if  v_sal>=3000 then

      v_tax:=v_sal*0.08;

    elsif  v_sal>=1500 then  

       v_tax:=v_sal*0.06;

    else

        v_tax:=v_sal*0.04;

    end if;  

    DBMS_OUTPUT.PUT_LINE('应缴税金:'||v_tax);

  end;

3  要求:涉及表为scott.emp,输入一个员工号,修改该员工的工资,如果该员工为10号部门(deptno),则要求工资增加100;若为20号部门,要求工资增加150;若为30号部门,工资增加200;否则增加300。

DECLARE

     v_deptno scott.emp.deptno%type;

     v_zj NUMBER(4);

     v_empno  scott.emp.empno%type;

BEGIN

      v_empno:='7788';

     SELECT deptno INTO v_deptno FROM scott.emp WHERE empno=v_empno;

     IF        v_deptno=10          THEN v_zj:=100;

     ELSIF v_deptno=20          THEN v_zj:=150;

     ELSIF v_deptno=30          THEN v_zj:=200;

     ELSE    v_zj:=300;

  END IF;

  UPDATE scott.emp SET sal=sal+v_zj  WHERE empno='7788';

END;

多分枝:

declare

   v_deptno  scott.emp.deptno%type;

   v_zl  scott.emp.sal%type;

begin

   select deptno into v_deptno  from  scott.emp  where empno=&&a;

   if v_deptno=10 then

       v_zl:=100;

     elsif   v_deptno=20 then

        v_zl:=150;

          elsif   v_deptno=30 then

          v_zl:=200;

     else

     v_zl:=300;

     end if;

     

     UPDATE scott.emp SET sal=sal+v_zl  WHERE empno=&a;

等职比较:

DECLARE

   v_deptno emp.deptno%type;

   v_increment NUMBER(4);

   v_empno  emp.empno%type;

BEGIN

  v_empno:=&x;

 SELECT deptno INTO v_deptno FROM emp WHERE empno=v_empno;

  CASE v_deptno  

    WHEN 10 THEN v_increment:=100;

    WHEN 20 THEN v_increment:=150;

    WHEN 30 THEN v_increment:=200;

    ELSE  v_increment:=300;

END CASE;

UPDATE emp SET sal=sal+v_increment WHERE empno=v_empno;

if SQL%FOUND then

  dbms_output.put_line('更改成功');

   select sal into v_sal from scott.emp where empno='7788';

   dbms_output.put_line(v_sal);

end  if;

END;

例: 关于成绩等级制和百分制的相互转换。

---简单case表达式

declare

  grade  varchar2(4):='良好';

begin

  case grade

    when '优秀' then dbms_output.put_line('大于等于90');

    when '良好' then dbms_output.put_line('大于等于80,小于90');

    when '及格' then dbms_output.put_line('大于等于60,小于80');

    else dbms_output.put_line('不及格');

 end case;

end;    

例: 关于成绩等级制和百分制的相互转换。

---搜索case表达式

declare

  score  int:=91;

begin

  case

    when score>=90 then dbms_output.put_line('优秀');

    when score>=80 then dbms_output.put_line('良好');

    when score>=60 then dbms_output.put_line('及格');

    else dbms_output.put_line('不及格');

 end case;

end;

select  xh,xm,zxf,

(case

    when zxf>50 then 'gao'

      when zxf>=40 then 'zhong'

        else '学分不够,需继续'

end) as

 huodexuefenqingkuang  from xs;

注意:

  1.  整个case 语句没有标点符号
  2.  case 语句的结束用end 而非end case
  3.  then 之后没有dbms_output.put_line().
  4.  as 之后无引号.

检验图书是否过期:

select empno,ename,job,hiredate,

(case

    when trunc(sysdate-HIREDATE)>360  then '过期'

    when hiredate is null then '没借书'

     else  '没过期'

    end)

   as 是否过期 from scott.emp;

【例】下面是一个异常处理的例子:

SET SERVEROUTPUT ON;

DECLARE

    x NUMBER;

BEGIN

    x:= 'aa123';

EXCEPTION

   WHEN VALUE_ERROR THEN

     DBMS_OUTPUT.PUT_LINE('数据类型错误');

END;

!!!!!

与数据库有关的一段异常:查找“李明”同学的学号 ★

DECLARE

    v_result xs.xm%TYPE;

    BEGIN

    SELECT xh INTO v_result

             FROM xs

             WHERE xm='李明';

    DBMS_OUTPUT.PUT_LINE('The student number is '||v_result);

    EXCEPTION

           WHEN TOO_MANY_ROWS THEN

              DBMS_OUTPUT.PUT_LINE('There has TOO_MANY_ROWS error');

           WHEN NO_DATA_FOUND THEN

             DBMS_OUTPUT.PUT_LINE('There has NO_DATA_FOUND error');

          WHEN OTHERS THEN

            DBMS_OUTPUT.PUT_LINE('错误情况不明');

END;

查询名为SMITH的员工工资,如果该员工不存在,则输出“There is not such an employee!”;如果存在多个同名的员工,则输出'There has too_many_rows error!”

declare

 v_sal scott.emp.sal%type;

begin

    select sal into v_sal from scott.emp where ename='SMITH';

   DBMS_OUTPUT.PUT_LINE(v_sal);

  EXCEPTION

       WHEN NO_DATA_FOUND THEN

             DBMS_OUTPUT.PUT_LINE(‘没有返回数据');

       WHEN TOO_MANY_ROWS THEN

             DBMS_OUTPUT.PUT_LINE(‘返回多行匹配数据');

 end;

注意:使用others异常可以借助两个函数来说明捕捉到的异常的类型-----SQLCODE和SQLERRM

DECLARE

      v_result number;

    BEGIN

      SELECT xm INTO v_result

        FROM xs

        WHERE xh='010010';

      DBMS_OUTPUT.PUT_LINE('The student name is'||v_result);

      EXCEPTION

           WHEN OTHERS THEN

               DBMS_OUTPUT.PUT_LINE('the sqlcode is'||SQLCODE);

               DBMS_OUTPUT.PUT_LINE('the sqlERRM is'||SQLERRM);

    END;

修改7844员工的工资(增加1000),保证修改后工资不超过6000。

DECLARE

  e_1 EXCEPTION;

  v_sal scott.emp.sal%TYPE;

BEGIN

     UPDATE scott.emp SET sal=sal+1000 WHERE empno=7844 ;

      select sal into v_sal from scott.emp  where empno=7844;

     --- 取出更新后的工资

     IF v_sal>4000 THEN

           RAISE e_1;

     END IF;

    EXCEPTION

    WHEN e_1 THEN

            DBMS_OUTPUT.PUT_LINE('The salary is too large!');

    ROLLBACK;

END;

练习:更新scott.emp中7788员工的工资,若没有成功,请抛出异常。

declare

    v_empno  scott.emp.empno%type;

    no_result  EXCEPTION;

Begin

   v_empno:=&a;

    update scott.emp  set sal=sal+100 where empno=v_empno;

    if  SQL%NOTFOUND   then

         raise no_result;

    end if;

exception

    when  no_result then

       dbms_output.put_line('数据没有更新');

    when others then

       dbms_output.put_line(sqlcode||'   '||sqlerrm);

end;

select deptno,empno,sal,hiredate ,(case

  when trunc(sysdate-hiredate)>5000 then 'guoqi'

  when hiredate is null then '没借书'

    else ''

  1.  as 是否借书,

  (case

  when trunc(sysdate-hiredate)>5000 then  to_char(trunc(sysdate-hiredate)*0.1)

      else ''

      end) as  罚款

 from scott.emp

Merge  只看红色的即可

/*示例程序块2   重要*/

  DECLARE

    v_xm varchar2(8):='Jame';

v_zym varchar2(10):='计算机';

v_zxf number(2):=45;    /*定义变量类型*/

BEGIN

               UPDATE XS  SET zxf=v_zxf

           WHERE xm=v_xm;

     IF SQL%NOTFOUND THEN

                DBMS_OUTPUT.PUT_LINE('没有该人,需要插入该人');

      INSERT INTO XS(XH,XM,ZYM,ZXF)          VALUES('007',v_xm,v_zym,v_zxf);

    END IF;

end;  

应用场合:对于特定的数据,在一次批量操作过程中,如果数据已经存在,则对存在的数据按照现有情况进行更新,如果不存在,则需要加入数据库。可以采用 Oracle 的 merge。

 说明:products为目标表,newproducts为源表,则若产品号相匹配,根据源表信息修改目标表的产品名(product_name)和产品类别(category)

merge into products p

     using newproducts np

          on (p.product_id=np.product_id)

when matched then

           update set

           p.product_name=np.product_name,

           p.category=np.category;

  WHEN NOT MATCHED THEN             INSERT(a.xh,a.xm,a.zym,a.xb,a.cssj,a.zxf)

    Values(b.xh,b.xm,b.zym,b.xb,b.cssj,b.zxf);

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

一个merge例子带update,delete 和insert 三种操作。

MERGE INTO products p

 USING newproducts np

 ON (p.product_id = np.product_id)

  WHEN MATCHED THEN

     UPDATE

    SET p.product_name = np.product_name,

    p.category = np.category

    DELETE WHERE (p.category = 'ELECTRNCS')

 WHEN NOT MATCHED THEN

    INSERT

VALUES (np.product_id, np.product_name, np.category)

[例]使用UNION ALL操作符,对scott用户的emp表进行操作,获得员工编号大于7800或者所在部门编号为10的员工信息。使用ORDER BY语句将结果集按照deptno列升序排列输出。

select empno,ename,sal,deptno from scott.emp

  where empno>7800

   union all

  select empno,ename,sal ,deptno from    scott.emp   where deptno=10

  order by deptno ASC

游标!!!

declare

        cursor my_cursor

             is   select xh from xs;

         v_xh xs.xh%type;

begin

         open my_cursor;

         fetch my_cursor into v_xh;

          dbms_output.put_line(v_xh);

          dbms_output.put_line(my_cursor%rowcount);

          Close my_cursor;  

   exception

       when others then

          dbms_output.put_line(sqlcode||sqlerrm);

【例2】下面介绍一个完整的游标应用实例:

DECLARE

     varId  NUMBER;

     varName VARCHAR2(50);   

        CURSOR MyCur(v_xb  xs.xb%type)   IS

           SELECT xh, xm FROM xs

          WHERE xb=v_xb;

Varxh=xs.xh%type;

Varname=xs.xm%type;

BEGIN

      OPEN MyCur(‘男’); --打开游标,参数为‘男’,表示读取信息为男同学信息

      FETCH MyCur INTO varId, varName;

      dbms_output.put_line('学生编号:'|| varxh||'学生名:'||varName ) ;

      CLOSE MyCur;

END;

游标的%isopen 属性练习

declare

   cursor  c_1 is select * from xs;

   v_1 c_1%rowtype;

begin

  if c_1%isopen=false then

         open c_1;

  end if;

  fetch c_1 into v_1;

  dbms_output.put_line(v_1.xh||v_1.xm||v_1.zxf);

  close c_1;

end;

最麻烦的

DECLARE

   TYPE emp_record_type IS RECORD(

        f_name   scott.emp.ename%TYPE,

        h_date   scott.emp.hiredate%TYPE);

   v_1   EMP_RECORD_TYPE;

   CURSOR c3(v_deptno NUMBER,v_job VARCHAR2)

 --声明游标,有参数有返回值

          RETURN EMP_RECORD_TYPE

   IS

      SELECT ename, hiredate FROM scott.emp

      WHERE deptno=v_deptno AND job =v_job;

BEGIN

   OPEN c3(v_job=>'MANAGER', v_deptno=>10);

 --打开游标,传递参数值

   LOOP

      FETCH c3 INTO v_1;    --提取游标

      IF c3%FOUND THEN

         DBMS_OUTPUT.PUT_LINE(v_1.f_name||'的雇佣日期是' ||v_1.h_date);

      ELSE

         DBMS_OUTPUT.PUT_LINE('已经处理完结果集了');

         EXIT;

      END IF;

   END LOOP;

   CLOSE c3;   --关闭游标

END;

大概率会考到

使用游标分别遍历xs表中的xh,zxf

DECLARE

      v_xh char(6);

       v_zxf number(2);

       CURSOR    XS_CUR3

            IS SELECT XH,ZXF FROM XS;

BEGIN

      OPEN XS_CUR3;

       FETCH XS_CUR3 INTO v_xh,v_zxf;

 WHILE XS_CUR3%FOUND

 LOOP

   dbms_output.put_line(v_xh||v_zxf);

   FETCH XS_CUR3 INTO v_xh,v_zxf;

  END LOOP;

  CLOSE XS_CUR3;

  END;

利用WHILE循环检索游标

DECLARE

    CURSOR cursor_name IS SELECT…;

BEGIN

    OPEN cursor_name;

    FETCH…INTO…;

    WHILE cursor_name%FOUND

     LOOP

           ……   

           FETCH…INTO…;

     END LOOP;

    CLOSE cursor;

END;

注:在打开游标后用fetch语句先取一行到变量,然后再用while对该游标进行判断,而不是打开后就立即用while进行判断 。

利用游标WHILE循环统计并输出scott.emp表各个部门的平均工资;若平均工资大于3000,则输出“该部门平均工资较高。”

DECLARE

  CURSOR c_dept_stat IS SELECT deptno,avg(sal) avgsal FROM scott.emp GROUP BY deptno;

  v_dept c_dept_stat%ROWTYPE;

BEGIN

  OPEN c_dept_stat;

  FETCH c_dept_stat INTO v_dept;

  WHILE c_dept_stat%FOUND LOOP

       DBMS_OUTPUT.PUT_LINE('部门号为'||v_dept.deptno||' '||'平均工资为'||trunc(v_dept.avgsal,1));

        FETCH c_dept_stat INTO v_dept;

  END LOOP;

  CLOSE c_dept_stat;

END;

利用FOR循环统计并输出各个部门的平均工资。

DECLARE

    CURSOR c_1 IS SELECT deptno,avg(sal) avgsal FROM scott.emp GROUP BY deptno;

    V_dept  c_1%ROWTYPE;

BEGIN

    FOR   v_dept    IN c_1

LOOP

    DBMS_OUTPUT.PUT_LINE(v_dept.deptno||' '||v_dept.avgsal);

  END LOOP;

END;

在For循环中直接使用select 子查询代替游标名

BEGIN

  FOR v_dept IN (SELECT deptno,avg(sal) avgsal FROM scott.emp GROUP BY deptno)

  LOOP

    DBMS_OUTPUT.PUT_LINE(v_dept.deptno||' '||v_dept.avgsal);

  END LOOP;

END;

DECLARE

   v_empno  scott.emp.empno%TYPE;

   v_sal      scott.emp.sal%TYPE;

   CURSOR c_cursor IS SELECT empno,sal FROM scott.emp where sal<1200 for update;

 begin

      open c_cursor;

      LOOP

      FETCH c_cursor INTO v_empno, v_sal;

      EXIT WHEN c_cursor%NOTFOUND;

             UPDATE scott.emp SET Sal=Sal+50 WHERE current of c_cursor;

            DBMS_OUTPUT.PUT_LINE('编码为'||v_empno||'工资已更新!');

      DBMS_OUTPUT.PUT_LINE('记录数:'|| c_cursor%ROWCOUNT);

   END LOOP;

   CLOSE c_cursor;

END;

修改scott.emp表员工的工资,如果员工的部门号为10,工资提高100;部门号为20,工资提高150;部门号为30,工资提高200;否则工资提高250。

DECLARE

  CURSOR c_emp IS SELECT * FROM scott.emp FOR UPDATE      of zl nowait;

   v_zl NUMBER;

   v_emp c_emp%rowtype;

BEGIN

     FOR v_emp IN c_emp LOOP

        CASE v_emp.deptno

             WHEN 10 THEN v_zl:=100;

             WHEN 20 THEN v_zl:=150;

             WHEN 30 THEN v_zl:=200;

             ELSE                v_zl:=250;

       END CASE;

    UPDATE scott.emp SET sal=sal+v_zl WHERE CURRENT OF c_emp;

  END LOOP;

END;

不懂!

declare

       type t_dept is REF CURSOR  return scott.emp%rowtype;

       c_1 t_dept;

       v_row  scott.emp%rowtype;

    begin

       open c_1 for select * from scott.emp where  deptno=10;

       fetch c_1 into v_row;

       dbms_output.put_line(v_row.empno||' ' ||v_row.job);

       close c_1;

       

       open c_1 for select * from scott.emp where sal>=2000;

       fetch c_1 into v_row;

       dbms_output.put_line(v_row.deptno||' ' ||v_row.job);

       close c_1;

     end;

存储过程

create or replace procedure update_emp

 as

 begin

  update scott.emp set ename='candy' where empno=7876;

end update_emp;

猜你喜欢

转载自blog.csdn.net/mnhdxhcky/article/details/85265788