web-dev-qa-db-ja.com

Oracleでsequence.nextvalをnullにするにはどうすればよいですか?

私はそのように定義されたOracleシーケンスを持っています:

CREATE SEQUENCE  "DALLAS"."X_SEQ"  
    MINVALUE 0 
    MAXVALUE 999999999999999999999999999 
    INCREMENT BY 1 START WITH 0 NOCACHE  NOORDER  NOCYCLE ;

ストアドプロシージャでレコードを挿入するために使用されます。

PROCEDURE Insert_Record
                (p_name    IN  VARCHAR2,                
                 p_userid  IN  INTEGER,
                 cur_out   OUT TYPES_PKG.RefCursor)
    IS
        v_id NUMBER := 0;
    BEGIN
        -- Get id value from sequence
        SELECT x_seq.nextval
          INTO v_id
          FROM dual;

        -- Line below is X_PKG line 40
        INSERT INTO X
            (the_id,            
             name,                        
             update_userid)
          VALUES
            (v_id,
             p_name,                        
             p_userid);

        -- Return new id
        OPEN cur_out FOR
            SELECT v_id the_id
              FROM dual;
    END;

このプロシージャは、アプリケーションコードから実行するとエラーが返される場合があります。

ORA-01400: cannot insert NULL into ("DALLAS"."X"."THE_ID") 
ORA-06512: at "DALLAS.X_PKG", line 40 
ORA-06512: at line 1

関連するかどうかに関係なく詳細:

  • Oracle Database 11g Enterprise Editionリリース11.2.0.1.0-64ビット本番
  • プロシージャは、Microsoft.Practices.EnterpriseLibrary-Data.Oracle.OracleDatabase.ExecuteReader(DbCommandコマンド)を介して実行されます。
  • アプリケーションは、明示的なトランザクションで呼び出しをラップしません。
  • 挿入が断続的に失敗する-1%未満

どのような状況でx_seq.nextval nullになりますか?

11
Corbin March

私はこれがあなたのコードのアーチファクトになるか、あなたが使っている.netドライバになると確信しています。純粋なSQL-PL/SQLを使用して簡単なデモを作成しましたが、シーケンス値が失われることはありません。ちなみに、使用しているrefカーソルはおそらく不要であり、コードのパフォーマンスと可読性に影響を与える可能性があります-私のデモには、一貫して10%以上高速に実行するinsert_record2プロシージャが含まれています-私のラップトップでは約26秒で、refカーソルバージョンでは36秒です。少なくとも理解しやすいと思います。監査トリガーを備えたテストデータベースに対して、変更されたバージョンを実行できることは明らかです。

/* 
demo for dbse 
assumes a user with create table, create sequence, create procedure pivs and quota. 

*/

drop table dbse13142 purge;

create table dbse13142(
    the_id number not null
,   name   varchar2(20)
,   userid number)
;

drop sequence x_seq;
CREATE SEQUENCE  X_SEQ NOCACHE  NOORDER  NOCYCLE ;

create or replace PROCEDURE Insert_Record
                (p_name    IN  VARCHAR2,                
                 p_userid  IN  INTEGER,
                 cur_out   OUT sys_refcursor)
    IS
        v_id NUMBER := 0;
    BEGIN
        -- Get id value from sequence
        SELECT x_seq.nextval
          INTO v_id
          FROM dual;

        -- Line below is X_PKG line 40
        INSERT INTO dbse13142
            (the_id,            
             name,                        
             userid)
          VALUES
            (v_id,
             p_name,                        
             p_userid);

        -- Return new id
        OPEN cur_out FOR
            SELECT v_id the_id
              FROM dual;
    END;
/


create or replace PROCEDURE Insert_Record2
                (p_name    IN  VARCHAR2,                
                 p_userid  IN  INTEGER,
                 p_theid   OUT dbse13142.the_id%type)
    IS
    BEGIN
        -- Get id value from sequence
        SELECT x_seq.nextval
          INTO p_theid
          FROM dual;

        -- Line below is X_PKG line 40
        INSERT INTO dbse13142
            (the_id,            
             name,                        
             userid)
          VALUES
            (p_theid,
             p_name,                        
             p_userid);
    END;
/

set timing on

declare
   c sys_refcursor;
begin   
for i in 1..100000 loop
   insert_record('User '||i,i,c);
   close c;
end loop;
commit;
end;
/

select count(*) from dbse13142;
truncate table dbse13142;

declare
  x number;
begin   
for i in 1..100000 loop
   insert_record2('User '||i,i,x);
end loop;
commit;
end;
/

select count(*) from dbse13142;
truncate table dbse13142;
4

テストケースを試してみてください。ダミーテーブルを作成し、データベースからのシーケンスを使用して100,000レコードを挿入します。問題ないと思います。次に、アプリケーションから同じものを挿入してみます。

これは、Oracleクライアントの不一致などの他の問題が原因である可能性がありますか?

問題を解決するが問題は解決しない別の解決策は、テーブルにトリガーを追加することです。
Dallas.Xのテーブルに挿入する前IF:the_idがnullである場合SELECT x_seq.nextval INTO:the_id FROM dual;終了IF;

2
kevinsky

私はまだコメントする特権を持っていないので、これを答えとして書きます:Oracleバージョン> = 11.1を使用しているため、SQLではなく PL/SQL式のシーケンス を使用できるので、これを試してください:

   v_id := x_seq.nextval;

これの代わりに:

 -- Get id value from sequence
    SELECT x_seq.nextval
      INTO v_id
      FROM dual;

または、「。currval」を使用するときに疑問/落とし穴を聞いたことがありますが、v_idの個別の割り当てを省略して、このコードのみを使用することはできますか?

 -- Line below is X_PKG line 40
        INSERT INTO X
            (the_id,            
             name,                        
             update_userid)
          VALUES
            (x_seq.nextval,
             p_name,                        
             p_userid);

        -- Return new id
        OPEN cur_out FOR
            SELECT x_seq.currval the_id
              FROM dual;

申し訳ありませんが、これを試すための11gインスタンスがありません。

0
George3