Oracle使用游标

Oracle创建过程示例

在此示例中,将在user表中插入记录,所以需要先创建user表。

user表创建语句:

create table myuser(id number(10) primary key,name varchar2(10));

现在编写程序代码以在user表中插入记录。

程序代码:

create or replace procedure "insertuser"    
(id in number,    
name in varchar2)    
is    
begin    
    insert into myuser values(id,name);    
end;    
/

执行上面代码,得到以下结果 -

Procedure created.
Oracle程序调用过程

让我们来看看如何调用上面创建的过程。参考以下示例代码 -

begin    
   insertuser(101,'Maxsu');  
   dbms_output.put_line('record inserted successfully');    
end;    
/

现在,查看USER表中的记录,将看到上面插入了一条记录。

ID        Name
---------------------------
101        Maxsu
Oracle删除过程

语法

drop procedure procedure_name;

删除示例

drop procedure insertuser;

执行上面示例代码后,将删除上面创建的过程:INSERTUSER

if语句

create or replace function eval_frequency (emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE)
  RETURN PLS_INTEGER
AS
  h_date     EMPLOYEES.HIRE_DATE%TYPE;
  today      EMPLOYEES.HIRE_DATE%TYPE;
  eval_freq  PLS_INTEGER;
BEGIN
  SELECT SYSDATE INTO today FROM DUAL;
  SELECT HIRE_DATE INTO h_date
  FROM EMPLOYEES
  WHERE EMPLOYEE_ID = eval_frequency.emp_id;
  IF ((h_date + (INTERVAL '120' MONTH)) < today) THEN
    eval_freq := 1;
  ELSE
    eval_freq := 2;
  END IF;
  RETURN eval_freq;
END eval_frequency;
/
-----call

case语句

    CASE j_id
       WHEN 'PU_CLERK' THEN DBMS_OUTPUT.PUT_LINE(
         'Consider 8% salary increase for employee # ' || emp_id);
       WHEN 'SH_CLERK' THEN DBMS_OUTPUT.PUT_LINE(
         'Consider 7% salary increase for employee # ' || emp_id);
       WHEN 'ST_CLERK' THEN DBMS_OUTPUT.PUT_LINE(
         'Consider 6% salary increase for employee # ' || emp_id);
       WHEN 'HR_REP' THEN DBMS_OUTPUT.PUT_LINE(
         'Consider 5% salary increase for employee # ' || emp_id);
       WHEN 'PR_REP' THEN DBMS_OUTPUT.PUT_LINE(
         'Consider 5% salary increase for employee # ' || emp_id);
       WHEN 'MK_REP' THEN DBMS_OUTPUT.PUT_LINE(
         'Consider 4% salary increase for employee # ' || emp_id);
       ELSE DBMS_OUTPUT.PUT_LINE(
         'Nothing to do for employee #' || emp_id);
    END CASE;
  ELSE
    eval_freq := 2;
  END IF;

the FOR LOOP语句

FOR i IN 1..5 LOOP
          sal := sal * (1 + sal_raise);
          DBMS_OUTPUT.PUT_LINE(ROUND(sal, 2) || ' after ' || i || ' year(s)');
        END LOOP;

while loop语句

WHILE sal <= sal_max LOOP
  sal := sal * (1 + sal_raise);
  DBMS_OUTPUT.PUT_LINE(ROUND(sal, 2));
END LOOP;

一、使用记录

关于记录(Record)

由单行多列的标量构成的复合结构。可以看做是一种用户自定义数据类型。组成类似于多维数组。将一个或多个标量封装成一个对象进行操作。是一种临时复合对象类型。 记录可以直接赋值。RECORD1 :=RECORD2; 记录不可以整体比较。 记录不可以整体判断为空。

%ROWTYPE和记录(Record)

请区别%ROWTYPE和记录(Record)类型。%ROWTYPE可以说是Record的升级简化版。 区别在与前者结构为表结构,后者为自定义结构。二者在使用上没有很大区别。前者方便,后者灵活。在实际中根据情况来具体决定使用。Record + PL/SQL表可以进行数据的多行多列存储。

声明一个RECORD类型,然后声明该类型的变量。

TYPE record_name IS RECORD
( field_name data_type [:= initial_value]
[, field_name data_type [:= initial_value ] ]... );

variable_name record_name;

例一、记录可以整体赋值

create table empa as select * from emp;
declare 
  type emp_type is record(
    empno number(4),
    ename varchar2(10),
    job varchar2(15),
    sal number(7,2),
    deptno number(2)
  );
emp_rec1 emp_type;
emp_rec2 emp_type;
begin
  emp_rec1.empno := 12;
  emp_rec1.ename := '李白';
  emp_rec1.job := 'poem';
  emp_rec1.sal := 800;
  emp_rec1.deptno := 10;
  emp_rec2 := emp_rec1;
  dbms_output.put_line(emp_rec2.empno);
end;

记录不可以整体比较,只可以比较记录字段

记录不可以整体判断为空,只可以判断记录字段

例二、使用%TYPE和%ROWTYPE动态指定记录字段

/*create table empa as select * from emp;*/
declare 
  type my_rec_type is record(
    reno empa.empno%type,
    rename empa.ename%type,
    rjob empa.job%type
  );
emp_rec my_rec_type;
begin
   select empno, ename, job  into emp_rec  from empa where empa.empno = '7369';
  If emp_rec.rjob = 'CLERK' Then
    DBMS_OUTPUT.PUT_LINE('Name: ' || emp_rec.RENAME);
  End If;
End;

二、使用游标

游标的概念

​ 游标是SQL的一个内存工作区,由系统或用户以变量的形式定义。游标的作用就是用于临时存储从数据库中提取的数据块。在某些情况下,需要把数据从存放在磁盘的表中调到计算机内存中进行处理,最后将处理结果显示出来或最终写回数据库。这样数据处理的速度才会提高,否则频繁的磁盘数据交换会降低效率。

游标有两种类型:显式游标和隐式游标。在前述程序中用到的SELECT…INTO…查询语句,一次只能从数据库中提取一行数据,对于这种形式的查询和DML操作,系统都会使用一个隐式游标。但是如果要提取多行数据,就要由程序员定义一个显式游标,并通过与游标有关的语句进行处理。显式游标对应一个返回结果为多行多列的SELECT语句。

游标一旦打开,数据就从数据库中传送到游标变量中,然后应用程序再从游标变量中分解出需要的数据,并进行处理。

隐式游标

如前所述,DML操作和单行SELECT语句会使用隐式游标,它们是:

  • 插入操作:INSERT。
  • 更新操作:UPDATE。
  • 删除操作:DELETE。
  • 单行查询操作:SELECT … INTO …。

当系统使用一个隐式游标时,可以通过隐式游标的属性来了解操作的状态和结果,进而控制程序的流程。隐式游标可以使用名字SQL来访问,但要注意,通过SQL游标名总是只能访问前一个DML操作或单行SELECT操作的游标属性。所以通常在刚刚执行完操作之后,立即使用SQL游标名来访问属性。游标的属性有四种,如下所示。

--隐式游标的属性 返回值类型   意   义   
SQL%ROWCOUNT    --整型 代表DML语句成功执行的数据行数   
SQL%FOUND   --布尔型 值为TRUE代表插入、删除、更新或单行查询操作成功   
SQL%NOTFOUND    --布尔型 与SQL%FOUND属性返回值相反   
SQL%ISOPEN  --布尔型 DML执行过程中为真,结束后为假  

1 使用隐式游标的属性,判断对雇员工资的修改是否成功。 输入和运行以下程序:

SET SERVEROUTPUT ON    
BEGIN  
   UPDATE empa SET sal=sal+100 WHERE empno=7369;   
   IF SQL%FOUND THEN 
     DBMS_OUTPUT.PUT_LINE('成功修改雇员工资!'); 
     COMMIT;
   ELSE DBMS_OUTPUT.PUT_LINE('修改雇员工资失败!');   
   END IF;    
END; 
/

显式游标

1.声明游标

declear部分按以下格式声明游标:

cursor 游标名[(参数1 数据类型[,参数2 数据类型...])] is select语句; 参数是可选部分,所定义的参数可以出现在select语句的where子句中。如果定义了参数,则必须在打开游标时传递相应的实际参数。

select语句是对表或视图的查询语句,甚至也可以是联合查询。可以带where条件、order bygroup by等子句,但不能使用into子句。在select语句中可以使用在定义游标之前定义的变量。

2.打开游标

在可执行部分,按以下格式打开游标:

open 游标名[(实际参数1[,实际参数2...])];

打开游标时,select语句的查询结果就被传送到了游标工作区。

3.提取数据

在可执行部分,按以下格式将游标工作区中的数据取到变量中。提取操作必须在打开游标之后进行。

fetch 游标名 into 变量名1[,变量名2...];

fetch 游标名 into 记录变量;

游标打开后有一个指针指向数据区,fetch语句一次返回指针所指的一行数据,要返回多行需重复执行,可以使用循环语句来实现。控制循环可以通过判断游标的属性来进行。

下面对这两种格式进行说明: 第一种格式中的变量名是用来从游标中接收数据的变量,需要事先定义。变量的个数和类型应与select语句中的字段变量的个数和类型一致。 第二种格式一次将一行数据取到记录变量中,需要使用%rowtype事先定义记录变量,这种形式使用起来比较方便,不必分别定义和使用多个变量。 定义记录变量的方法如下:

变量名 表名|游标名%rowtype;

其中的表必须存在,游标名也必须先定义。

4.关闭游标

close 游标名;

显式游标打开后,必须显式地关闭。游标一旦关闭,游标占用的资源就被释放,游标变成无效,必须重新打开才能使用。

1 用游标提取emp表中7788雇员的名称和职务。

set serveroutput on
declare
  v_ename varchar2(10);
  v_job varchar2(10);
  cursor emp_cursor is select ename, job from emp where empno=7788;
begin
  open emp_cursor;
  fetch emp_cursor into v_ename, v_job;
  dbms_output.put_line(v_ename || ',' || v_job);
  close emp_cursor;
end;
/

2 用游标提取emp表中7788雇员的姓名、职务和工资。 用记录变量。

set serveroutput on
declare
  cursor emp_cursor is select ename, job, sal from emp;
  emp_record emp_cursor%rowtype;
begin
  open emp_cursor;
  fetch emp_cursor into emp_record;
  dbms_output.put_line(emp_record.ename || ',' || emp_record.job || ',' || emp_record.sal);
  close emp_cursor;
end;
/
--实例中使用记录变量来接收数据,记录变量由游标变量定义,需要出现在游标定义之后。

3 显示工资最高的前3名雇员的名称和工资。

set serveroutput on
declare
  cursor emp_cursor is select ename, sal from emp order by sal desc;
  emp_record emp_cursor%rowtype;
begin
  open emp_cursor;
  for i in 1..3 loop
      fetch emp_cursor into emp_record;
      dbms_output.put_line(emp_record.ename || ',' || emp_record.sal);
  end loop;
  close emp_cursor;
end;
/
--程序在游标定义中使用了ORDER BY子句进行排序,并使用循环语句来提取多行数据。

游标循环

1 使用特殊的FOR循环形式显示全部雇员的编号和名称。

set serveroutput on
declare
  cursor emp_cursor is select empno, ename from emp;
begin
  for emp_record in emp_cursor loop
      dbms_output.put_line(emp_record.empno || ',' || emp_record.ename);
  end loop;
end;
/
--可以看到该循环形式非常简单,隐含了记录变量的定义、游标的打开、提取和关闭过程。emp_record为隐含定义的记录变量,循环的执行次数与游标取得的数据的行数相一致。

2 另一种形式的游标循环。

set serveroutput on
begin
  for re in (select ename from emp) loop
      dbms_output.put_line(re.ename);
  end loop;
end;
/
--该种形式更为简单,省略了游标的定义,游标的SELECT查询语句在循环中直接出现。

显式游标属性

虽然可以使用前面的形式获得游标数据,但是在游标定义以后使用它的一些属性来进行结构控制是一种更为灵活的方法。显式游标的属性如下所示

--游标的属性   返回值类型   意   义   
%ROWCOUNT   --整型 获得FETCH语句返回的数据行数   
%FOUND  --布尔型 最近的FETCH语句返回一行数据则为真,否则为假   
%NOTFOUND   --布尔型 与%FOUND属性返回值相反   
%ISOPEN --布尔型 游标已经打开时值为真,否则为假  

emp_cursor%ISOPEN。如果游标已经打开,则返回值为“真”,否则为“假”。

1 使用游标的属性练习。

set serveroutput on
declare
  v_name varchar2(10);
  cursor emp_cursor is select ename from emp;
begin
  open emp_cursor;
  if emp_cursor%isopen then
      loop
          fetch emp_cursor into v_name;
          exit when emp_cursor%notfound;
          dbms_output.put_line(v_name);
      end loop;
  else
      dbms_output.put_line('用户信息:游标没有打开!');
  end if;
  close emp_cursor;
end;
/
--本例使用emp_cursor%ISOPEN判断游标是否打开;使用emp_cursor%ROWCOUNT获得到目前为止FETCH语句返回的数据行数并输出;使用循环来获取数据,在循环体中使用FETCH语句;使用emp_cursor%NOTFOUND判断FETCH语句是否成功执行,当FETCH语句失败时说明数据已经取完,退出循环。

游标参数的传递

1 带参数的游标。

set serveroutput on
declare
  v_empno number(5);
  v_ename varchar2(10);
  cursor emp_cursor(p_deptno number, p_job varchar2) is select empno, ename from emp where deptno = p_deptno and job = p_job;
begin
  open emp_cursor(10, 'CLERK');
  loop
      fetch emp_cursor into v_empno, v_ename;
      exit when emp_cursor%notfound;
      dbms_output.put_line(v_empno || ',' || v_ename);
  end loop;
  close emp_cursor;
end;
/
--游标emp_cursor定义了两个参数:p_deptno代表部门编号,p_job代表职务。语句OPEN emp_cursor(10, 'CLERK')传递了两个参数值给游标,即部门为10、职务为CLERK,所以游标查询的内容是部门10的职务为CLERK的雇员。循环部分用于显示查询的内容。

2 通过变量传递参数给游标。

set serveroutput on
declare
  v_empno number(5);
  v_ename varchar2(10);
  v_deptno number(5);
  v_job varchar2(10);
  cursor emp_cursor(p_deptno number, p_job varchar2) is select empno, ename from emp where deptno = p_deptno and job = p_job;
begin
  v_deptno := 10;
  v_job := 'CLERK';
  open emp_cursor(v_deptno, v_job);
  loop
      fetch emp_cursor into v_empno, v_ename;
      exit when emp_cursor%notfound;
      dbms_output.put_line(v_empno || ',' || v_ename);
  end loop;
  close emp_cursor;
end;
/

动态SELECT语句和动态游标的用法

Oracle支持动态select语句和动态游标,动态的方法大大扩展了程序设计的能力。 对于查询结果为一行的select语句,可以用动态生成查询语句字符串的方法,在程序执行阶段临时地生成并执行,语法是:

execute immediate 查询语句字符串 into 变量1[,变量2...];

1 动态select查询。

set serveroutput on
declare
  str varchar2(100);
  v_ename varchar2(10);
begin
  str := 'select ename from scott.emp where empno=7788';
  execute immediate str into v_ename;
  dbms_output.put_line(v_ename);
end;
/
--SELECT...INTO...语句存放在STR字符串中,通过EXECUTE语句执行。

在变量声明部分定义的游标是静态的,不能在程序运行过程中修改。虽然可以通过参数传递来取得不同的数据,但还是有很大的局限性。通过采用动态游标,可以在程序运行阶段随时生成一个查询语句作为游标。要使用动态游标需要先定义一个游标类型,然后声明一个游标变量,游标对应的查询语句可以在程序的执行过程中动态地说明。

定义游标类型的语句如下:

type 游标类型名 ref cursor;

声明游标变量的语句如下: 游标变量名 游标类型名; 在可执行部分可以如下形式打开一个动态游标:

open 游标变量名 for 查询语句字符串;

1 按名字中包含的字母顺序分组显示雇员信息。

set serveroutput on
declare      
    type cur_type is ref cursor;     
    cur cur_type;     
    rec scott.emp%rowtype;     
    str varchar2(50);     
    letter char := 'A';   
begin    
    loop                 
      str:= 'select ename from emp where ename like ''%'||letter||'%''';         
      open cur for str;         
      dbms_output.put_line('包含字母'||letter||'的名字:');           
      loop             
            fetch cur into rec.ename;             
            exit when cur%notfound;
            dbms_output.put_line(rec.ename);  
        end loop;         
      exit when letter='Z';         
      letter := chr(ascii(letter)+1);     
    end loop;   
end;  
/
--使用了二重循环,在外循环体中,动态生成游标的SELECT语句,然后打开。通过语句letter:=chr(ascii(letter)+1)可获得字母表中的下一个字母。

异常处理 /错误处理

错误是在标准包中由系统预定义的标准错误,或是由用户在程序的说明部分自定义的错误。 语句序列就是不同分支的错误处理部分。 凡是出现在WHEN后面的错误都是可以捕捉到的错误,其他未被捕捉到的错误,将在WHEN OTHERS部分进行统一处理,OTHENS必须是EXCEPTION部分的最后一个错误处理分支。如要在该分支中进一步判断错误种类,可以通过使用预定义函数SQLCODE( )和SQLERRM( )来获得系统错误号和错误信息。 如果在程序的子块中发生了错误,但子块没有错误处理部分,则错误会传递到主程序中。

下面是由于查询编号错误而引起系统预定义异常的例子。 1 查询编号为1234的雇员名字。

set serveroutput on
declare
    v_ename varchar2(10);
begin
    select ename into v_ename from emp where empno = 1234;
    dbms_output.put_line(v_ename);
    exception
        when NO_DATA_FOUND then
            dbms_output.put_line('编号错误,没有找到雇员!');
            dbms_output.put_line('错误代码:'|| SQLCODE( ));   
            dbms_output.put_line('错误信息:' ||SQLERRM( )); 
        when OTHERS then
            dbms_output.put_line('发生其他错误');
end;
/
--在以上查询中,因为编号为1234的雇员不存在,所以将发生类型为“NO_DATA_ FOUND”的异常。“NO_DATA_FOUND”是系统预定义的错误类型,EXCEPTION部分下的WHEN语句将捕捉到该异常,并执行相应代码部分。在本例中,输出用户自定义的错误信息“编号错误,没有找到相应雇员!”。如果发生其他类型的错误,将执行OTHERS条件下的代码部分,显示“发生其他错误!”。

常见的系统预定义异常如下所示。

--错误名称        错误代码        错误含义   
CURSOR_ALREADY_OPEN ORA_06511   试图打开已经打开的游标   
INVALID_CURSOR  ORA_01001   试图使用没有打开的游标   
DUP_VAL_ON_INDEX    ORA_00001   保存重复值到惟一索引约束的列中   
ZERO_DIVIDE ORA_01476   发生除数为零的除法错误   
INVALID_NUMBER  ORA_01722   试图对无效字符进行数值转换   
ROWTYPE_MISMATCH    ORA_06504   主变量和游标的类型不兼容   
VALUE_ERROR ORA_06502   转换、截断或算术运算发生错误   
TOO_MANY_ROWS   ORA_01422   SELECT…INTO…语句返回多于一行的数据   
NO_DATA_FOUND   ORA_01403   SELECT…INTO…语句没有数据返回   
TIMEOUT_ON_RESOURCE ORA_00051   等待资源时发生超时错误   
TRANSACTION_BACKED_OUT  ORA_00060   由于死锁,提交失败   
STORAGE_ERROR   ORA_06500   发生内存错误   
PROGRAM_ERROR   ORA_06501   发生PL/SQL内部错误   
NOT_LOGGED_ON   ORA_01012   试图操作未连接的数据库   
LOGIN_DENIED    ORA_01017   在连接时提供了无效用户名或口令  

如果一个系统错误没有在标准包中定义,则需要在说明部分定义,语法如下: 错误名 EXCEPTION; 定义后使用PRAGMA EXCEPTION_INIT来将一个定义的错误同一个特别的Oracle错误代码相关联,就可以同系统预定义的错误一样使用了。语法如下:PRAGMA EXCEPTION_INIT(错误名,- 错误代码);

1 定义新的系统错误类型。

set serveroutput on
declare
    v_ename varchar2(10);
    NULL_INSERT_ERROR exception;
    pragma exception_init(NULL_INSERT_ERROR, -1400);
begin
    insert into emp(empno) values(null);
    exception
        when NULL_INSERT_ERROR then
            dbms_output.put_line('无法插入NULL值!');
        when OTHERS then
            dbms_output.put_line('其他错误!');
end;
/

自定义异常

程序设计者可以利用引发异常的机制来进行程序设计,自己定义异常类型。可以在声明部分定义新的异常类型,定义的语法是: 错误名 EXCEPTION; 用户定义的错误不能由系统来触发,必须由程序显式地触发,触发的语法是: RAISE 错误名; RAISE也可以用来引发模拟系统错误,比如,RAISE ZERO_DIVIDE将引发模拟的除零错误。 使用RAISE_APPLICATION_ERROR函数也可以引发异常。该函数要传递两个参数,第一个是用户自定义的错误编号,第二个参数是用户自定义的错误信息。使用该函数引发的异常的编号应该在20 000和20 999之间选择。

1 插入新雇员,限定插入雇员的编号在7000~8000之间。

set serveroutput on
declare
    new_no number(10);
    new_excp1 exception;
    new_excp2 exception;
begin
    new_no := 6788;
    insert into emp(empno, ename) values(new_no, 'LiBai');
    if new_no < 7000 then raise new_excp1;
    end if;
    if new_no > 8000 then raise new_excp2;
    end if;
    commit;
    exception
        when new_excp1 then
            rollback;
            dbms_output.put_line('雇员编号小于7000!');
        when new_excp2 then
            rollback;
            dbms_output.put_line('雇员号大于8000!');
        when OTHERS then
            dbms_output.put_line('其他错误');
end;
/
/* 使用RAISE_APPLICATION_ERROR函数引发系统异常。 
IF new_no<7000 THEN  
    ROLLBACK;   
    RAISE_APPLICATION_ERROR(-20001, '编号小于7000的下限!');   
END IF;   
*/

可以参考下面的程序片断将出错信息记录到表中,其中,errors为记录错误信息的表,SQLCODE为发生异常的错误编号,SQLERRM为发生异常的错误信息。

DECLARE 
  v_error_code      NUMBER; 
  v_error_message   VARCHAR2(255); 
BEGIN 
... 
EXCEPTION 
... 
WHEN OTHERS THEN 
    v_error_code := SQLCODE ; 
    v_error_message := SQLERRM ; 
    INSERT INTO errors 
    VALUES(v_error_code, v_error_message); 
END; 

索引表类型(关联数组)

该类型与数组相似,利用键值查找对应的数据,但是这里的键值同我们真正的数组下标不同,这种索引表的下标,还可以为字符串,真正的数组下标都是数字。索引表中的数据可以是上边介绍过的标量类型,也可以是记录类型。当在赋值的过程中,对已存在的索引表下标重复赋值,则会替换以前的数据。

set serveroutput on;
DECLARE
  /**
   *声明一个存储ly_ds整行数据的索引表,下标为数字,即 binary_integer
   */
  type index_row_type is table of ly_ds%rowtype
  index by binary_integer;
  /**
   *声明一个存储字符串数据的索引表,下标也为数字,即 pls_integer
   */
  type index_val_type is table of varchar2(10)
  index by pls_integer;
  /**
   *声明一个存储字符串数据的索引表,下标为字符串,即 varchar(100)、varchar(10),必须给固定大小
   */
  type index_str_val_type is table of varchar2(100)
  index by varchar(10);
   /**
    *定义一个下标为数字,存ly_ds一行的变量
    */
  v_row index_row_type; 
  /**
   *定义一个下标为数字,存字符串的变量
   */
  v_val index_val_type; 
  /**
   *定义一个下标为字符串,存字符串的变量
   */
  v_str_val index_str_val_type; 
BEGIN
 /**
  *为下标为数字的 字符串索引表下标1赋值
  */
  v_val(1) :='正数'; 
  /**
  *为下标为数字的 字符串索引表下标-1赋值
  */
  v_val(-1) :='负数'; 
  dbms_output.put_line('v_val中下标1的值:'||v_val(1));
  dbms_output.put_line('v_val中下标-1的值:'||v_val(-1));
  /**
  *将改行数据赋值给行变量的下标1上
  */
  select * into v_row(1) from ly_ds where id='2'; 
  dbms_output.put_line('v_row(1)中ly_mc的值:'||v_row(1).ly_mc);
  dbms_output.put_line('v_row(1)中ly_nl的值:'||v_row(1).ly_nl);
   /**
    *为下标为字符串的 字符串索引表的下标one赋值
    */
  v_str_val('one') :='java天下第一';  
   /**
    *为下标为字符串的 字符串索引表的下标test赋值
    */
  v_str_val('test') :='java天下无敌'; 
   /**
    *为下标为字符串的 字符串索引表的下标test1赋值
    */
  v_str_val('test1') :='java太可怕了'; 
  dbms_output.put_line('v_str_val中下标one的值:'||v_str_val('one'));
  dbms_output.put_line('v_str_val中下标test的值:'||v_str_val('test'));
  dbms_output.put_line('v_str_val中第一个值的下标:'||v_str_val.first);
  dbms_output.put_line('v_str_val中第一个下标对应的值:'||v_str_val(v_str_val.first));
  dbms_output.put_line('v_str_val中最后一个下标:'||v_str_val.last);
END;

varry变长数组

varry 数组,是另一种存储有序元素的集合。集合下标从1开始,比较适合较少的数据使用。具体如下:   它有一个注意的地方,就是数组在定义一个变量时候,一定要初始化 ,并且,在使用前 一定要先确定容量 。对于,在初始化时,已赋值的,可以不用定义存储的大小了。

set serveroutput on;
DECLARE
  /**
   *声明一个最多容纳100个数的varry数组,注意,它的下标是从1开始的。
   *即 binary_integer
   */
  type array_type is varray(100) of varchar(100);
  /**
   *分别定义一个直接赋值的和两个未赋值的数组。
   *注意:一定要初始化,但可以不赋值。对于没有赋值的这种数组,在用之前
   *也一定要先确定容量。
   */
  v_val_array array_type := array_type('one','two');
  v_val_array2 array_type := array_type();
  v_val_array3 array_type := array_type();
BEGIN
   /**
    *获取第一个varry数组中的值
    *varry的下标从1开始
    */
    dbms_output.put_line('v_val_array中下标1的值:'||v_val_array(1));
    dbms_output.put_line('v_val_array中下标2的值:'||v_val_array(2));
   /**
    *获取第二个varry数组中的值
    *因为第二个varry没有初始化长度,所以通过extend方法,
    *为该数组加一个空位
    */
    v_val_array2.extend;
    v_val_array2(1) :='aaa'; 
    v_val_array2.extend;
    v_val_array2(2) :='bbb'; 
    v_val_array2.extend;
    v_val_array2(3) :='ccc'; 
    dbms_output.put_line('v_val_array2中下标1的值:'||v_val_array2(1));
    dbms_output.put_line('v_val_array2中下标2的值:'||v_val_array2(2));
    dbms_output.put_line('v_val_array2中下标3的值:'||v_val_array2(3));
  /**
    *获取第二个varry数组中的值
    *因为第二个varry没有初始化长度,所以通过extend方法,
    *为该数组初始化长度
    */
    v_val_array3.extend(v_val_array2.count());
    v_val_array3(1) :='ddd'; 
    v_val_array3(2) :='eee'; 
    v_val_array3(3) :='fff'; 
    dbms_output.put_line('v_val_array3中下标1的值:'||v_val_array3(1));
    dbms_output.put_line('v_val_array3中下标2的值:'||v_val_array3(2));
    dbms_output.put_line('v_val_array3中下标3的值:'||v_val_array3(3));
END;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值