zoukankan      html  css  js  c++  java
  • oracle insert into 获取自动增长列值

    在SQLServer中,插入一条记录,获取该行的标识列非常简单
    insert into table_name() values();select @@identity;
    在C# ado.net中,直接sqlcommand类的executescalar()方法就能获取刚刚插入语句的标识列

    Oracle中没有这么方便的方式,那么如何获取insert into后,返回的标识列的值呢?
    涉及到两个知识点:
    1.关于Oracle标识列的自增问题(sequence、trigger、nextval、currval)
    2.execute immediate 执行DML(insert into)的问题


    Oracle标识列的自增问题
    1.在网上看的最多的就是采用创建sequence+trigger的方式

    create sequence seq_Dishes
    minvalue 100
    start with 100
    increment by 1
    nomaxvalue
    nocycle
    nocache;
    
    create or replace trigger TG_seq_Dishes
    before insert on Dishes for each row
    begin
      select seq_Dishes.nextval into :new.DishId from dual;
    end;

    验证时,发现标识列每次自增是原来的两倍

    原因:insert into时触发器将原来准备好的正确的标识列值赋给下表的dishid,但是在插入过程中,该标识列值就变成了seq_dishes.currval,结果又发现values中有一个新的seq_dishes.nextval,所以当然会将新的标识列值赋给dishid了。

    insert into Dishes(dishid,DishName,UnitPrice,CategoryId) values(seq_dishes.nextval,'西红柿',10,2);

    如果执行下句,则会改变标识列的值,是当前查询到的结果变成seq_dishes.currval

    select seq_dishes.nextval from dual;

    2.不用触发器,则每次在insert语句中必须包含标识列字段,dishid(seq_dishes.nextval)

    insert into Dishes(dishid,DishName,UnitPrice,CategoryId) values(seq_dishes.nextval,'西红柿',10,2);

    最后需要说明的是,任何对 CURRVAL 的引用返回指定序列的当前值,该值是最后一次对 NEXTVAL 的引用所返回的值。用 NEXTVAL生成一个新值以后,可以继续使用 CURRVAL 访问这个值,不管另一个用户是否增加这个序列,currval使用时,必须放在nextval所在的回话中,且先有nextval,后面用户才能使用currval调用。

    注:Oracle的标识列自增非常执着,如匿名存储过程执行一半出错,但是执行了insert into语句,或者执行单个的insert into语句,再rollback,标识列都会更新。

    declare
      idx number;
    begin
      insert into Dishes(DishName,UnitPrice,CategoryId) values('西红柿',10,2);
      select seq_dishes.currval into idx from dual;
      dbms_output.put_line(idx);
      commit;
    end;

    execute immediate用于在块中执行SQL语句(execute immediate 执行DML语句,不会自动commit)


    一般方式:

    declare
      insrt_sql varchar2(200);
    begin
      insrt_sql := 'insert into Dishes(DishName,UnitPrice,CategoryId) values(''烧鸡'',23,2)';
      execute immediate insrt_sql;
      commit;
    end;

    通过占位符的方式传参,并执行insert语句:

    declare
      insrt_sql varchar2(200);
    begin
      insrt_sql := 'insert into Dishes(DishName,UnitPrice,CategoryId) values(:1,:2,:3)';
      execute immediate insrt_sql using '烧鸡',244,2;
      commit;
    end;

    通过定义变量,赋值的方式:

    declare
      insrt_sql varchar2(200);
      dishname varchar2(20):='烧鸡';
      price number := 200;
      idx number := 2;
    begin
      insrt_sql := 'insert into Dishes(DishName,UnitPrice,CategoryId) values('|| '''' || dishname || '''' || ',' || price || ','|| idx ||')';
      execute immediate insrt_sql;
      commit;
    end;

    将上面的匿名块封改成命名存储过程,并执行OK:

    create or replace procedure usp_querysequence
    (
      dishname varchar2,
      price number,
      idx number
    )
    is
      insrt_sql varchar2(200);
    begin
      insrt_sql := 'insert into Dishes(DishName,UnitPrice,CategoryId) values(';
      insrt_sql := insrt_sql || '''' || dishname || '''' || ',' || price || ','|| idx ||')';
      execute immediate insrt_sql;
      commit;
    end;
    
    execute usp_querysequence('烤鱼',250,3);

    将insert语句变成参数,放入存储过程,并在匿名块中调用该存储过程:

    create or replace procedure usp_querysequence
    (
      insrt_sql varchar2
    )
    is
    begin   execute immediate insrt_sql;   commit; end; declare   insrt_sql varchar2(200); begin   insrt_sql := 'insert into Dishes(DishName,UnitPrice,CategoryId) values(''烧鸡'',23,2)';   usp_querysequence(insrt_sql); end;

    最后,oracle数据库insert后获取insert数据的自增id值:(ADO.net中,可以直接调用该存储过程)

    create or replace procedure usp_querysequence
    (
      insrt_sql in varchar2,
      SEQ_NAME in varchar2,
      newid out number
    )
    is
      str_sql varchar(100);
    begin
      execute immediate insrt_sql;
      str_sql := 'select '||SEQ_NAME||'.CURRVAL from dual ' ;
      execute immediate str_sql into newid;
      commit;
    end;

    程序模拟调用存储过程,执行OK

    declare
      insrt_sql varchar2(200);
      seq_name varchar2(20) := 'seq_dishes';
      newid number := 0;
    begin
      insrt_sql := 'insert into Dishes(DishName,UnitPrice,CategoryId) values(''烤肉'',15,2)';
      usp_querysequence(insrt_sql,seq_name,newid);
      dbms_output.put_line(newid);
    end;
  • 相关阅读:
    深入方法(22)- 指针参数
    深入方法(21)- 开放数组参数
    深入方法(20)- 静态数组参数
    深入方法(19)- 过程中的方法
    深入方法(18)- 在接口区声明的方法都相当于提前声明了
    深入方法(17)- 提前声明
    WNMP(Windows + Nginx + PHP + MySQL) 安装
    Yii2框架 数据库常用操作
    Python 生成器与迭代器 yield 案例分析
    Python VS PHP 基础语法
  • 原文地址:https://www.cnblogs.com/pandora2050/p/15113004.html
Copyright © 2011-2022 走看看