Java Web笔记(四) - PL / SQL

PL / SQL

1 PL / SQL中常用的数据类型

oracle中的数据类型PL / SQL都支持。

PL / SQL的数据类型

    record类型(类似Java中的Map)注:只能存放一条记录

    table类型(类似Java中的List

    varray 可变长度数组类型

    %type 基于某个表中的字段的类型

    %rowtype 基于某个表中的所有字段的类型(和record类似)注:只能存放一条记录

    cursor 游标数据类型

2 PL / SQL结构

declare(有遍历声明写)

-- 声明变量

begin(必写)

-- 处理SQL

[exception](有异常写)

-- 处理异常

end;(必写)

示例:

declare
-- 声明变量
    v_name varchar2(20);
    v_id number := 1; -- := 是赋值符号
    
    -- 声明一个名字为myrecord的record的类型(只能存放一条数据)
    type myrecord is record (
        id number,
        -- name varchar2(50)
        -- 当不知道name的类型应该定义成什么时,可以用这种方式定义
        name t_user.name%type -- 表示name的类型是基于t_user表中的name字段的类型
    );
    -- 声明一个myrecord的变量
    v_record myrecord;
    
    -- 当声明的record的字段与某个表的字段都相同时,可以使用%rowtype声明(只能存放一条数据)
    v_record2 t_user%rowtype;
    
    -- 声明一个名字为mytable的table的类型(可以存放多条数据)
       -- List<String>
    type mytable is table of varchar2(50); -- of后面定义类型中的数据类型
    -- 声明一个mytable的变量
    v_table mytable;
    
    -- 声明一个名字为myarray,长度最大为50的varray类型(必须要指定最大长度)
    type myarray is varray(50) of number; -- of后面定义数据类型
    -- 声明一个myarray的变量
    v_array myarray := myarray(); -- 声明
    
    -- 游标
        -- is后跟查询语句
       cursor mycursor is
           select * from t_user;
begin
-- 处理SQL
    -- 查询用户表id为1的用户名,并打印出来
      -- 注:1. 使用into将查询的结果赋值给变量
      --     2. 多个字段赋值变量,变量与字段要一一对应,不然容易出现数据类型不一致
      -- select id, name into v_id, v_name from t_user where id=1;
      -- PL/SQL打印语句
      dbms_output.put_line(v_name);
    
    -- 使用record保存查询结果
      -- 注:1. 查询字段要与v_record中定义的类型和顺序要一致
      --     2. v_record中的字段不能比查询出的字段长度短
      select id, name into v_record from t_user where id=1;
      dbms_output.put_line(v_record.id || '---' || v_record.name);
    
    -- %rowtype的使用
    select * into v_record2 from t_user where id=1;
    dbms_output.put_line(v_record2.id || '---' || v_record2.name);
    
    -- table
    --select name into v_table from t_user;
    
    -- varray
      -- 往varray中存值
      v_array.extend(50); -- 扩容,必须先扩容才能存放
      -- 注:oracle中数组下标是从1开始,存放数据时可以不连续
      v_array(1) := 1;
      v_array(2) := 2;
      v_array(3) := 3;
      dbms_output.put_line(v_array(3)); -- 获取元素值
      dbms_output.put_line(v_array.count()); -- 获取长度
      dbms_output.put_line(v_array.limit()); -- 获取最大长度
end;

流程控制语句

1)判断语句

    if 条件 then

        语句

    elsif 条件 then

        语句

    else 语句

    end if; -- 必须写

示例:

-- 流程控制
declare
    v_name t_user.name%type;
begin
  select name into v_name from t_user where id=&id; -- &id是可以动态输入参数,运行时oracle会提示你输入值
  
  -- 判断语句(oracle中,=就是判断相等的符号)
  if v_name = 'zhangsan' then
      dbms_output.put_line('张三');
  elsif v_name = 'lisi' then
      dbms_output.put_line('李四');
  else
      dbms_output.put_line('王五');
  end if; -- 结束要写end if
end;

2)循环语句

    loop exit when 退出条件 ... end loop;

    while ... loop ... end loop;

    for ... in ... loop ... end loop;

示例:
declare
    v_sum number := 0;
    i number := 1;
begin
  -- 求1到10的和
  -- 方式1
  loop
    exit when i >10; -- 退出循环的条件(不写退出条件默认是死循环)
    v_sum := v_sum + i;
    i := i + 1;
  end loop;
  -- 输出和
  dbms_output.put_line(v_sum);
  
  -- 方式2
  v_sum := 0;
  i := 1;
  while i<=10 loop
    v_sum := v_sum +i;
    i := i + 1;
  end loop;
  dbms_output.put_line(v_sum);
  
  -- 方式3
  v_sum := 0;
  i := 1;
  for k in 1..10 loop
    v_sum := v_sum +i;
    i := i + 1;
  end loop;
  dbms_output.put_line(v_sum);
end;

数据库游标

1)游标的四个属性

    %found:表示后面还有记录

    %notfound:表示已经提取完毕

    %isopen:游标是否已经打开

    %rowcount:代表fetch到的记录个数

2)遍历游标

示例1

declare
    -- 1. 声明游标
    cursor cur is select * from t_user;
    myrecord t_user%rowtype; -- 声明保存一条t_user数据的变量
begin
    -- 2. 打开游标
    open cur;
    -- 3. 提取游标
    loop
      fetch cur into myrecord;
      exit when cur%notfound;
      dbms_output.put_line(myrecord.name);
    end loop;
    -- 4. 关闭游标
    close cur;
end;

示例2(掌握):

declare
    -- 声明游标
    cursor cur is select * from t_user;
begin
    -- 注:使用for循环遍历游标不需要打开和关闭游标
    -- for循环会自动打开和关闭
    -- 提取游标
    for c in cur loop -- c:元素遍历名;cur:遍历对象
      dbms_output.put_line(c.name);
    end loop;
end;

存储过程

语法:

        create or replace procedure cunqian ( -- create or replace代表创建或者替换

            -- 传递的参数

            -- 不允许指定参数类型的长度

            -- out只能作为赋值和打印

        ) as

    -- 声明变量

begin

    -- 程序体

end;

参数的模式

    in:表示参数只能输入(默认为in

    out:表示参数只能输出,out只能作赋值和打印

    in out:表示参数既可以作为输入,也可以作为输出

示例:

-- 创建存储过程
create or replace procedure cunqian (
    v_id in number, -- 不允许指定类型的长度,默认参数模式是in类型
    v_email out varchar2, -- out只能做赋值和打印
    v_addmoney in out number -- 要增加的钱
) as
    v_money t_user_info.money%type; -- 保存查出的钱
begin
  -- 查询用户姓名和钱数
  select email, money into v_email, v_money from t_user_info where id=v_id;
  -- 将用户的钱加上添加的钱数
  v_addmoney := v_money + v_addmoney;
  -- 修改该用户的数据
  update t_user_info set money=v_addmoney where id=v_id;
  -- 提交事务
  commit;
end;
-- 调用存储过程
declare
    v_email varchar2(50);
    v_addmoney number := 10;
begin
  cunqian(1, v_email, v_addmoney);
  dbms_output.put_line(v_email);
end;

函数

语法

    函数的参数模式一般为输入参数。

    create or replace function 函数名(参数1, 参数2, ...)

    return 数据类型

    as/is

        PRAGMA AUTONOMOUS_TRANSACTION; --开启自治事务,用来解决在查询语句中不能使用DML语句

        -- 声明变量

        begin

            -- 程序

        end;

示例:

-- 创建函数
create or replace function zhuanzhang(
    v_id number, -- 转账用户
    u_id number, -- 到账用户
    v_money t_user_info.money%type -- 转账金额
)
return number
is
    PRAGMA AUTONOMOUS_TRANSACTION; -- 开启自治事务
    v_m t_user_info.money%type; -- 存储用户金额
    v_n number; -- 存储用户个数
begin
    -- 查询转账用户
    select money into v_m from t_user_info where id=v_id;
    /*判断转账用户的金额是否满足转账*/
    if v_money < v_m then
      -- 满足转账
      v_m := v_m - v_money;
      update t_user_info set money=v_m where id=v_id;
      -- 判断到账用户是否存在
      select count(1) into v_n from t_user_info where id=u_id;
      if v_n > 0 then
        -- 到账用户存在
        update t_user_info set money=v_money+money where id=u_id;
        commit;
      else
        rollback;
      end if;
    end if;
    return (v_m);
end;
-- 调用函数
select zhuanzhang(1,2,36) from dual; -- 基于伪表

触发器(一般不推荐使用)

语法

create or replace trigger 触发器名

before/after insert/update/delete on 表名 [for each row]

-- for each row:行级触发,不写默认是表级触发

declare

begin

end;

示例1(使用触发器设置插入数据的主键id):

create or replace trigger batchInsertUser
before insert on t_user for each row
declare
begin
  /* 往t_user表中插入数据时,使用触发器给id赋值 */
  -- :new代表赋值给新的id
  -- :old代表老值,一般更新、删除使用
  select t_user_seq.nextval into :new.id from dual;
  :new.name := '123'; -- 插入时将名字设置为’123’
end;
insert into t_user (name, password) values('zhouliu', '333');

-- 查看序列当前值
select t_user_seq.currval from dual;

示例2(备份数据):

/*
    场景二:备份数据,在出入数据是备份用户id和插入时间
*/
-- 创建备份表
create table t_user_bak (
    userId number, -- 用户id
    createTime date -- 插入时间
)
-- 创建触发器
create or replace trigger user_bak
before insert on t_user for each row
declare
begin
  select t_user_seq.nextval into :new.id from dual;
  insert into t_user_bak(userId, createTime)
  values(:new.id, sysdate); -- sysdate: 获取系统当前时间
end;
insert into t_user (name, password) values('liming', '555');

select * from t_user;
select * from t_user_bak;

示例三:

/*
    场景三:修改数据前,将老数据备份到备份表中
*/
-- 创建备份表
create table t_user_bak2 as
select * from t_user where 1=2;
-- 创建触发器
create or replace trigger user_bak2
before update on t_user for each row
declare
begin
  insert into t_user_bak2(id, name, password, ip)
  values(:old.id, :old.name, :old.password, :old.ip);
end;
-- 修改t_user表的数据
update t_user set name='456' where id=13

select * from t_user;
select * from t_user_bak2;

动态SQL

语法

execute immediate ‘语句’ [using 参数1, 参数2, ...]

示例:

declare
  v_str varchar(100);
begin
  -- :v1是占位符
  v_str := 'update t_user set password=:v1 where id=:v2';
  execute immediate v_str using '555', 19;
end;

select * from t_user; 

异常处理

语法

declare

v_name t_user.name%type;

myexception exception; -- 自定义异常

begin

exception

where 异常名 then

处理语句(例如打印)

end;

1)预定义异常的名字

ZERO_DIVIDE (除数不能为0)

NO_DATA_FOUND (没有查询到数据的异常)

注:异常名字可以通过文档查询。

示例:

declare
  v_name t_user.name%type;
begin
  select name into v_name from t_user where id=100;
  dbms_output.put_line(v_name);
exception
  when NO_DATA_FOUND then
    dbms_output.put_line('未找到数据');
end;
2)对其他异常的处理

when others then ...

示例:

declare
  v_name t_user.name%type;
begin
  select name into v_name from t_user where id=100;
  dbms_output.put_line(v_name);
exception
  when others then
    dbms_output.put_line('未找到数据');
end;
3)自定义异常

在声明变量的部分声明一个异常  异常名 exception

raise 异常名; 抛出异常

示例:

declare
  v_name t_user.name%type;
  myexception exception; -- 定义自定义异常
begin
  raise myexception; -- raise: 抛出异常
exception
  when myexception then
    dbms_output.put_line('自定义处理异常');
end;
4)raise_application_error 来指定异常的 code msg

其中code的设置范围是 -20000 -20999

获取code使用 SQLCODE  

获取消息 使用 SQLERRM

示例:

declare
begin
  raise_application_error(-20001,'错误信息');
exception
  when others then
    dbms_output.put_line(SQLCODE || SQLERRM);
end;

merge into语句

作用

既可以更新操作,也可以插入操作。

语法

merge into 表名1 别名1

using (table | view | sub_query) 别名2

on (join condition)

when matched then

update 表名

set col1 = col_val1

col2 = col_val2

when not matched then

insert (column_list) values (column_values);

Oracle中查询树结构的SQL语句

表结构:

create table t_user_tree (
    userId number primary key,
    username varchar2(50),
    password varchar2(32),
    pid number references t_user_tree(userId)
);

SQL语句:

select * from t_user_tree
start with userId = 1 // 根节点id
connect by prior userId = pid // 根节点=父节点
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值