2012-10-23 13 views
1

我有一個腳本,我希望有一個全局變量來存儲事務編號供以後使用。代碼在一個模式下工作正常,我所提取的序列值相對較低。它沒有在具有更高序列值的另一個架構上工作,我得到「數值溢出」。如果我將該序列值更改爲較低的數字,它的工作原理也是如此,但這不是一個選項。選擇大的序列值到全局變量不工作在PL/SQL代碼

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) 

無效。

任何想法,我可以嘗試或其他方式來存儲全球狀態?

+1

一想:爲什麼不把號碼存儲在臨時表中? – slashmais

+0

使用臨時表確實是一種替代方案,如果使用變量是不可能的,我將回退到這種情況。謝謝。 – Tobias

+0

沒有問一個重要的問題......你在SQL Developer或SQL * Plus中運行這個問題嗎?我可以用SQL Developer(在32位Windows上針對Linux上的64位數據庫,或者在32位Linux上針對Linux上的32位數據庫)獲得同樣的錯誤,但在SQL * Plus中並不如此。 (我想知道32位SQL * Plus對64位數據庫是否會有問題,但它現在看起來更像是一個開發者錯誤)。 –

回答

1

在進一步的調查中,這看起來可能是一個SQL開發人員的錯誤(假設你正在做什麼,當然......)。我可以得到同樣的錯誤:

VAR TRANSACTIONNR NUMBER; 

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

看來,SQL Developer的NUMBER僅限於2^31,這是不正常的情況下爲Oracle。

一個可能的解決方法是使用BINARY_FLOAT存儲的價值,但最終你還是會碰到精度問題(不知道在哪裏,但看起來OK高達2^53 -ish),並且你需要cast()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; 
/

出於某種原因,我似乎不能夠在匿名塊我將它再次參考綁定變量 - 它在註釋掉的代碼空 - 這似乎是另一個SQL Developer的怪癖,不管var類型;但正如你在你的代碼這樣做,我可以再次假設太多...


爲後人原來的答覆,因爲它仍然可能在其他情況下,相關...

推測你正在做一些事情來結束當前的交易,例如在endtransaction中的commit;否則,您可以在撥打電話do_something時參考my_sequence.currval。 A 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(): 

注意在包被報告對6號線的錯誤,這是for ... loop行,而不是來自匿名塊中的賦值。

這樣的循環當然是一件很奇怪的事情,但可能有其他方法來產生該錯誤。它的工作斷點是nextval高於2^31。如果我用2147483647開始序列,那麼2147483648就會出錯。

我假設你實際上從原始問題得到ORA-01426;如果它實際上是ORA-1438ORA-06502那麼通過嘗試將值分配給number(9)列或變量可以更容易地進行重現。 '數字溢出'雖然非常具體。

+0

謝謝,有趣的是循環會導致相同的錯誤。但爲什麼它發生在我「選擇MY_SEQUENCE.NEXTVAL INTO:TRANSACTIONNR」的行?爲什麼當我使用在DECLARE塊中聲明的變量時,它不會發生? – Tobias

+0

@Tobias - 你確定它在那條線上嗎?您能否將錯誤的堆棧跟蹤添加到問題中?也許包裝規格,或者如果你沒有打電話給任何包裝程序,就會發生這種情況。也許還可以確認你真正的第一個匿名塊沒有異常處理程序。 –