首页 > 代码库 > 7.PL_SQL——在PL_SQL程序中内嵌查询语句、DML语句和事物处理语句

7.PL_SQL——在PL_SQL程序中内嵌查询语句、DML语句和事物处理语句

    在PL/SQL中可以使用的SQL语句主要有以下几类:

       SELECT 查询语句,DML语句,Transaction 事物处理语句,本文将对这几类语句在PL/SQL中的用法逐一介绍。

一、查询语句—SELECT

      SELECT 语句用来查询一条或多条语句。虽然SELECT 语句也属于DML语句,但SELECT是只读的,所以单独列出。

PL/SQL中使用SELECT 语句的格式如下

 

SELECT select_list

INTO {variable_name[,variable_name]...

| record_name}

FROM table

[WHERE condition];

}

 

          这里INTO是必选项,是指将查询出来的结果导入到变量中,因此INTO 后面跟的变量个数、数据类型和顺序必须和SELECT 后面跟的选项个数、数据类型以及顺序一致。

         如果使用record这种变量类型,可以一次性导入而不需要逐一指明(后文将详解)。

要使用INTO,查询结果只能有一条(行)记录,否则会发生混淆。下面看这个例子:

 

SQL> edit

DECLARE

--      v_fname VARCHAR2(25);
        v_fname employees.first_name%TYPE;
BEGIN
        SELECT first_name INTO v_fname
        FROM employees WHERE employee_id = 200;
 
        DBMS_OUTPUT.PUT_LINE(‘First Name is: ‘|| v_fname);
END;
/

 

SQL> /

FirstName is: Jennifer
PL/SQLprocedure successfully completed.

如果现在要查询的employee_id 大于等于200,那么会出现什么结果呢?

SQL> edit

DECLARE
       v_fname employees.first_name%TYPE;
BEGIN
        SELECT first_name INTO v_fname
        FROM employees WHERE employee_id >=200;
 
        DBMS_OUTPUT.PUT_LINE(‘First Name is: ‘|| v_fname);
END;
/

 

SQL> /

DECLARE
*
ERRORat line 1:
ORA-01422:exact fetch returns more than requested number of rows
ORA-06512:at line 5
-- 报错了,提示查询结果多余1条


 

现在再来看一个查询多列的例子(注意,仍然是1行结果):

 

SQL> edit

DECLARE
        v_emp_hiredateemployees.hire_date%TYPE;
        v_emp_salary   employees.salary%TYPE;
BEGIN
        SELECT hire_date, salary
        INTO v_emp_hiredate, v_emp_salary
                -- 查询了两列记录,需要注意的是,数据个数、数据类型和顺序必须一一对应
        FROM employees
        WHERE employee_id = 100;
 
        DBMS_OUTPUT.PUT_LINE(‘Hire date is :‘|| v_emp_hiredate);
        DBMS_OUTPUT.PUT_LINE(‘Salary is : ‘ ||v_emp_salary);
END;
/

 

SQL> /

Hiredate is : 17-JUN-03
Salaryis : 24000
PL/SQLprocedure successfully completed.

 

除了基本的查询函数外,一些聚合函数也可以直接在PL/SQL中使用,只要保证这些聚合函数的运行结果仍然是一行记录即可:

 

SQL> edit

DECLARE
        v_sum_sal NUMBER(10,2);
        v_deptno  NUMBER NOT NULL := 60;
BEGIN
        SELECT SUM(salary) -- group function
                                -- 使用了SQL中的聚合函数SUM()
                                --SUM()的结果仍然是一行
        INTO  v_sum_sal
                                -- 将SUM()函数的运行结果导入到变量v_sum_sal中
        FROM  employees
        WHERE department_id = v_deptno;
        DBMS_OUTPUT.PUT_LINE(‘The sum of salaryis ‘|| v_sum_sal);
END;

 

SQL> /

Thesum of salary is 28800
PL/SQLprocedure successfully completed.

 

如果要查询多条记录并导入变量,则需要涉及游标的概念,游标将在后文中详解。

 

二、PL/SQL中使用DML语句

           PL/SQL中也可以使用DML语句来修改数据库中的表,DML语句主要指的是INSERT, UPDATE,DELETEMERGE等语句,其中INSERT,UPDATE,DELETE  多半只涉及一张表,而MERGE则涉及两张表,如果两张表的数据不一致,就使用其中一张表来更新另外一张。

wKioL1P08wuAxXglAAELKwdpopc486.jpg

         下面来看DML语句中INSERT使用的例子:

SQL> edit

BEGIN
        INSERT INTO employees
        (employee_id, first_name,last_name,email,
        hire_date,job_id,salary)
        VALUES(employees_seq.NEXTVAL,‘Ruth‘,‘Cores‘,       ‘RCORES‘,CURRENT_DATE,‘AD_ASST‘,4000);
END;
/

SQL> /

PL/SQLprocedure successfully completed.

SQL> select * from employees wherefirst_name like ‘Ruth‘;

 EMPLOYEE_ID FIRST_NAME           LAST_NAME
------------------------------- -------------------------
EMAIL                     PHONE_NUMBER         HIRE_DATE JOB_ID         SALARY
--------------------------------------------- --------- ---------- ----------
COMMISSION_PCTMANAGER_ID DEPARTMENT_ID
------------------------ -------------
        207 Ruth                 Cores
RCORES                                                                14-AUG-14 AD_ASST          4000

 

再来看一个UPDATE的例子:

SQL> edit

DECLARE
        sal_increase employees.salary%TYPE :=800;
BEGIN
        UPDATE employees
        SET   salary = salary + sal_increase
        WHERE job_id = ‘ST_CLERK‘;
END;
/

SQL> /

PL/SQLprocedure successfully completed.

 

PL/SQL中使用DELETE也很简单:

SQL> select * from tt

  -- 首先使用SQL语句查询所有的信息
        ID
----------
         0
         1

SQL> edit

DECLARE
        v_id tt.id%TYPE := 1;
BEGIN
        DELETE FROM tt
        WHERE id = v_id;
END;
/

SQL> /

 PL/SQL procedure successfully completed.

SQL> select * from tt;

        ID
----------
         0
-- 已经删除了一条记录


          INSERT, UPDATE,DELETE  语句基本上可以直接在PL/SQL中使用,和SQL语言并无差别。MERGE这种操作使用不多,下面举一个例子来简单介绍一下:

1. 先创建表ttt,并插入三条记录

SQL> create table ttt(t_id int,

  2 t_name varchar2(20));
Tablecreated.

SQL> insert into ttt values(0,‘a‘);

1row created.

SQL> insert into ttt values(1,‘b‘);

1row created.

SQL> insert into ttt values(2,‘c‘);

1row created.

SQL> select * from ttt;

      T_ID T_NAME
------------------------------
         0 a
         1 b
         2 c

2. 再创建表t2,插入一条记录

SQL> create table t2(t2_id int,

 2  t2_name varchar2(20)); 

  
Table created.

SQL> insert into t2 values(0,‘d‘);

1row created.

SQL> insert into t2 values(3,‘e‘);

1row created.

 SQL> select * from t2;

     T2_ID T2_NAME
------------------------------
         0 d
         3 e

3. 现在在PL/SQL中使用MERGE的方法用t2的数据来更新ttt的数据

SQL> edit

BEGIN
MERGEINTO ttt
      USING t2
      ON (ttt.t_id = t2.t2_id)
     WHEN MATCHED THEN
        UPDATE SET ttt.t_name = t2.t2_name
     WHEN NOT MATCHED THEN
        INSERT VALUES(t2.t2_id, t2.t2_name);
END;
/

SQL> select * from ttt;

-- 表ttt已经用t2合并更新了     
 T_ID T_NAME
------------------------------
         0 d
         1 b
         2 c
         3 e

 

DML语句操作数据库时,还可以使用Records来同时插入或更新一组数据,如下面这两个例子:

 

DECLARE
        my_book books%ROWTYPE;
BEGIN
        my_book.isbn := ‘1-56592-335-9‘;
        my_book.title := ‘Oracle PL/SQLProgramming 5th‘;
        my_book.summary := ‘General userguide‘;
        my_book.author := ‘Feusertein, Steven‘;
        my_book.page_count := 1000;
 
        INSERT INTO books VALUES my_book;
END;
/

 

DECLARE
        my_book books%ROWTYPE;
BEGIN
        my_book.isbn := ‘1-56592-335-9‘;
        my_book.title := ‘Oracle PL/SQLProgramming 5th‘;
        my_book.summary := ‘General userguide‘;
        my_book.author := ‘Feusertein, Steven‘;
        my_book.page_count := 1000;
 
        UPDATE books SET ROW = my_book
        WHERE isbin = my_book.isbn;
END;
/

          这两个例子中各条记录都保存在变量类型为Record的变量my_book中,然后将该变量作为一个整体插入或更新到表中。

          Records这种变量类型后文中将详解,这里只简要的介绍一下它的基本用法。

        INDEXDDL语句不能够直接使用,必须使用动态SQL语句的形式来使用。

 

三、事物控制语句(Transaction control

         事物控制语句主要指的是commitrollbacksavepoint

          PL/SQLBlock 事物(Transaction)之间没有一一对应的关系,可能一个PL/SQL的块已经结束了(如出现异常,退出程序了),但是事物(Tansaction)还没有被提交或者是回滚,就会导致数据的丢失。(相关知识后文会详解)另一方面,可能一个Transaction已经结束了,而PL/SQL block还在继续。一个Transaction可以跨越多个Block如上文中INSERT UPDATE的例子中,虽然对表做了修改,但并没有使用commit加以提交,因此Transaction还在继续。

wKiom1P08gnQshCVAADH0w8oaiI695.jpg

现在来看下面这个例子:

1. 首先以SYS用户登录

SQL> show user

USERis "SYS"

SQL> desc v$transaction

 Name                                      Null?    Type
 ------------------------------------------------- ----------------------------
 ADDR                                              RAW(4)
 XIDUSN                                            NUMBER
 XIDSLOT                                           NUMBER
 XIDSQN                                            NUMBER
 XID                                               RAW(8)

 

 SQL> select xid,xidusn from v$transaction;

norows selected
--当前没有记录


  2. 现在切换成hr用户

SQL> show user

USERis "HR"

SQL> create table tt (id int);

Tablecreated.

SQL> insert into tt values(0);

1row created.

 

3. 现在再次切换到SYS用户来查看xid这一行的记录

SQL> show user

USER is "SYS"

SQL> select xid,xidusn fromv$transaction

XID                                XIDUSN
------------------------------   ----------
040001009B020000                      4

 

4. 现在切换回hr用户,然后提交刚才的事物

SQL> show user

USERis "HR"

SQL> commit;

Commitcomplete.

SQL> select * from tt;

        ID
----------
         0

5. 此时再以SYS用户查看动态性能试图(v$transaction),就会发现刚才的记录消失了:

SQL> show user

USERis "SYS"

      

SQL> select xid,xidusn fromv$transaction;

no rows selected



本文出自 “重剑无锋 大巧不工” 博客,请务必保留此出处http://wuyelan.blog.51cto.com/6118147/1542885