1

後で使用するためにトランザクション番号を格納するグローバル変数が必要なスクリプトがあります。コードは、取得しているシーケンス値が比較的低い 1 つのスキーマで正常に動作しています。「数値オーバーフロー」が発生する、より高いシーケンス値を持つ別のスキーマでは機能していません。そのシーケンス値をより低い数値に変更すると、同様に機能しますが、それはオプションではありません。

VAR TRANSACTIONNR NUMBER;

BEGIN
  --Works with        NEXTVAL being around  946713241
  --Doesn't work with NEXTVAL being around 2961725541
  SELECT MY_SEQUENCE.NEXTVAL INTO :TRANSACTIONNR FROM DUAL;
  MY_PACKAGE.STARTTRANSACTION(:TRANSACTIONNR);
END;
/

  -- SQL Statements

BEGIN
  MY_PACKAGE.ENDTRANSACTION;
  MY_PACKAGE.DO_SOMETHING(:TRANSACTIONNR);
END;
/

DECLARE ブロックで宣言された変数にシーケンスを選択することも機能しています。

DECLARE
  TRANSACTIONNR NUMBER;
BEGIN
  SELECT MY_SEQUENCE.NEXTVAL INTO TRANSACTIONNR FROM DUAL;
  MY_PACKAGE.STARTTRANSACTION(TRANSACTIONNR);
END;
/

しかし、それは最後のブロックでそれを再利用できないことを意味します. 数字の大きさの設定はできません。

VAR TRANSACTIONNR NUMBER(15)

有効じゃない。

私が試すことができるアイデアや、グローバル状態を保存する他の方法はありますか?

4

1 に答える 1

1

さらに調査すると、これはSQL Developerのバグである可能性があります(もちろん、もう一度何をしているのかを推測しています...)。同じエラーが発生する可能性があります:

VAR TRANSACTIONNR NUMBER;

BEGIN
  SELECT 2961725541 INTO :TRANSACTIONNR FROM DUAL;
END;
/

SQL DeveloperNUMBERはに制限されているよう2^31ですが、これは通常のOracleには当てはまりません。

おそらく回避策は、値を格納するために使用することですが、最終的には精度の問題が発生し(どこにあるかはわかりませんが、 -ishBINARY_FLOATまでは問題ないように見えます)、使用時に元に戻す必要があります。2^53cast()NUMBER

VAR TRANSACTIONNR BINARY_DOUBLE;

BEGIN
  SELECT 2961725541 INTO :TRANSACTIONNR FROM DUAL;
  -- dbms_output.put_line(cast(:TRANSACTIONNR as NUMBER)); -- null for some reason
END;
/

...

BEGIN
  dbms_output.put_line(cast(:TRANSACTIONNR as NUMBER));
END;
/

var何らかの理由で、設定した匿名ブロックでバインド変数を再度参照できないようです。コメントアウトされたコードではnullです。これは、タイプに関係なく、別のSQLDeveloperの癖のようです。しかし、あなたがあなたのコードでそうしているので、私は再びあまりにも多くを仮定したかもしれません...


後世のための元の答え、それは他の状況にまだ関連しているかもしれないので...

おそらく、現在のトランザクションを終了するために何かをしていると思いcommitますendtransactionmy_sequence.currvalそれ以外の場合は、do_something呼び出しで参照することができます。ただし、変数はこのサイズのnumber数値には問題ありませんが、そのサイズのシーケンスに問題はなく、手動で割り当てられたものではなく、シーケンスからのものであることに違いはありません。問題はストレージやシーケンスにあるとは思いません。

エラーは、呼び出しているパッケージプロシージャのいずれかから発生している可能性が高いようですが、それを使用して何をしているのかは想像できません。ただし、このようなものは同じエラーを引き起こします:

create sequence my_sequence start with 2961725541;

create package my_package as
procedure starttransaction(v_num number);
procedure endtransaction;
procedure do_something(v_num number);
end my_package;
/

create package body my_package as

procedure starttransaction(v_num number) is
begin
    dbms_output.put_line('starttransaction(): ' || v_num);
    for i in 1..v_num loop
        null;
    end loop;
end starttransaction;

procedure endtransaction is
begin
    dbms_output.put_line('endtransaction()');
end endtransaction;

procedure do_something(v_num number) is
begin
    dbms_output.put_line('do_something(): ' || v_num);
end do_something;

end my_package;
/

それに対してコードを実行すると、エラーがスローされます。

BEGIN
*
ERROR at line 1:
ORA-01426: numeric overflow
ORA-06512: at "STACKOVERFLOW.MY_PACKAGE", line 6
ORA-06512: at line 5


endtransaction()
do_something():

エラーはfor ... loop、匿名ブロックの割り当てからではなく、パッケージの6行目に対して報告されることに注意してください。

もちろん、そのようにループするのは奇妙なことですが、そのエラーを生成する方法はおそらく他にもあります。それが機能するためのブレークポイントは、nextvalが上にある場合2^31です。シーケンスを2147483647で開始すると機能し、2147483648ではエラーになります。

私はあなたが実際にORA-01426元の質問から得ていると仮定しています。それが実際にORA-1438またはである場合は、値を列または変数ORA-06502に割り当てようとすることで、再現が容易になります。number(9)ただし、「数値オーバーフロー」はかなり具体的です。

于 2012-10-23T14:19:01.350 に答える