2013-07-17 162 views
7

我在想如果一個函數給出了變量的最大長度存在於plsql中。是否有可能獲得變量的最大可能長度

例如,如果我聲明

DECLARE 

varia VARCHAR2(7) 
BEGIN 
    call of a function that would return 7 
END 

即使雜物爲空,我能得到VARCHAR的長度爲7。

---爲例

create or replace 
TYPE ENREG_320_03 UNDER ENREG_320_BASE(
date_creation VARCHAR2(8), 
raison_sociale_emetteur VARCHAR2(35), 
adresse_emetteur_1 VARCHAR2(35), 
adresse_emetteur_2 VARCHAR2(35), 
adresse_emetteur_3 VARCHAR2(35), 
num_siret VARCHAR2(14), 
ref_remise VARCHAR2(16), 
code_bic_emetteur VARCHAR2(11), 
type_ident_compte_debit VARCHAR2(1), 
ident_compte_debit VARCHAR2(34), 
code_devise_compte_debit VARCHAR2(3), 
ident_client VARCHAR2(16), 
type_ident_compte_frais VARCHAR2(1), 
ident_compte_frais VARCHAR2(34), 
code_devise_compte_frais VARCHAR2(3), 
zone_reserve VARCHAR2(16), 
indice_type_debit_remise VARCHAR2(1), 
indice_type_remise VARCHAR2(1), 
date_execution_souhait VARCHAR2(8), 
devise_transfert VARCHAR2(3), 

MEMBER FUNCTION get_date_creation RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.date_creation IS NULL THEN lpad(' ', 8, ' ') ELSE rpad(SELF.date_creation, 8, ' ') END; 
END get_date_creation; 

MEMBER FUNCTION get_raison_sociale_emetteur RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.raison_sociale_emetteur IS NULL THEN lpad(' ', 35, ' ') ELSE rpad(SELF.raison_sociale_emetteur, 35, ' ') END; 
END get_raison_sociale_emetteur; 

MEMBER FUNCTION get_adresse_emetteur_1 RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.adresse_emetteur_1 IS NULL THEN lpad(' ', 35, ' ') ELSE rpad(SELF.adresse_emetteur_1, 35, ' ') END; 
END get_adresse_emetteur_1; 

MEMBER FUNCTION get_adresse_emetteur_2 RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.adresse_emetteur_2 IS NULL THEN lpad(' ', 35, ' ') ELSE rpad(SELF.adresse_emetteur_2, 35, ' ') END; 
END get_adresse_emetteur_2; 

MEMBER FUNCTION get_adresse_emetteur_3 RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.adresse_emetteur_3 IS NULL THEN lpad(' ', 35, ' ') ELSE rpad(SELF.adresse_emetteur_3, 35, ' ') END; 
END get_adresse_emetteur_3; 

MEMBER FUNCTION get_num_siret RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.num_siret IS NULL THEN lpad(' ', 14, ' ') ELSE rpad(SELF.num_siret, 14, ' ') END; 
END get_num_siret; 

MEMBER FUNCTION get_ref_remise RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.ref_remise IS NULL THEN lpad(' ', 16, ' ') ELSE rpad(SELF.ref_remise, 16, ' ') END; 
END get_ref_remise; 

MEMBER FUNCTION get_code_bic_emetteur RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.code_bic_emetteur IS NULL THEN lpad(' ', 11, ' ') ELSE rpad(SELF.code_bic_emetteur, 11, ' ') END; 
END get_code_bic_emetteur; 

MEMBER FUNCTION get_type_ident_compte_debit RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.type_ident_compte_debit IS NULL THEN lpad(' ', 1, ' ') ELSE rpad(SELF.type_ident_compte_debit, 1, ' ') END; 
END get_type_ident_compte_debit; 

MEMBER FUNCTION get_ident_compte_debit RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.ident_compte_debit IS NULL THEN lpad(' ', 34, ' ') ELSE rpad(SELF.ident_compte_debit, 34, ' ') END; 
END get_ident_compte_debit; 

MEMBER FUNCTION get_code_devise_compte_debit RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.code_devise_compte_debit IS NULL THEN lpad(' ', 3, ' ') ELSE rpad(SELF.code_devise_compte_debit, 3, ' ') END; 
END get_code_devise_compte_debit; 

MEMBER FUNCTION get_ident_client RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.ident_client IS NULL THEN lpad(' ', 16, ' ') ELSE rpad(SELF.ident_client, 16, ' ') END; 
END get_ident_client; 

MEMBER FUNCTION get_type_ident_compte_frais RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.type_ident_compte_frais IS NULL THEN lpad(' ', 1, ' ') ELSE rpad(SELF.type_ident_compte_frais, 1, ' ') END; 
END get_type_ident_compte_frais; 

MEMBER FUNCTION get_ident_compte_frais RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.ident_compte_frais IS NULL THEN lpad(' ', 34, ' ') ELSE rpad(SELF.ident_compte_frais, 34, ' ') END; 
END get_ident_compte_frais; 

MEMBER FUNCTION get_code_devise_compte_frais RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.code_devise_compte_frais IS NULL THEN lpad(' ', 3, ' ') ELSE rpad(SELF.code_devise_compte_frais, 3, ' ') END; 
END get_code_devise_compte_frais; 

MEMBER FUNCTION get_zone_reserve RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.zone_reserve IS NULL THEN lpad(' ', 16, ' ') ELSE rpad(SELF.zone_reserve, 16, ' ') END; 
END get_zone_reserve; 

MEMBER FUNCTION get_indice_type_debit_remise RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.indice_type_debit_remise IS NULL THEN lpad(' ', 1, ' ') ELSE rpad(SELF.indice_type_debit_remise, 1, ' ') END; 
END get_indice_type_debit_remise; 

MEMBER FUNCTION get_indice_type_remise RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.indice_type_remise IS NULL THEN lpad(' ', 1, ' ') ELSE rpad(SELF.indice_type_remise, 1, ' ') END; 
END get_indice_type_remise; 

MEMBER FUNCTION get_date_execution_souhait RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.date_execution_souhait IS NULL THEN lpad(' ', 8, ' ') ELSE rpad(SELF.date_execution_souhait, 8, ' ') END; 
END get_date_execution_souhait; 

MEMBER FUNCTION get_devise_transfert RETURN VARCHAR2 AS 
BEGIN 
    RETURN CASE WHEN SELF.devise_transfert IS NULL THEN lpad(' ', 3, ' ') ELSE rpad(SELF.devise_transfert, 3, ' ') END; 
END get_devise_transfert; 

所以我在想,如果一個簡單的函數存在獲取字段所以我沒有在干將使用數字的大小:如果字段的大小被改變,就沒有必要改變干將,它會制定出任何將varchar

但我明白這是不可能

謝謝大家的大小

+0

這是一個奇怪的要求。大小就在那裏,爲什麼你需要一個函數調用呢? – Mat

+0

,因爲如果有一天大小發生變化,還有另一部分代碼不需要更改 – mlwacosmos

+2

您可以基於列聲明變量(和代碼的其他部分,我假設它是另一個變量)在一張桌子裏;例如'聲明var tab.col%TYPE'?然後,如果表格定義更改,所有引用都會被更改。取決於你當然如何使用它 - 例如,如果你在填充時需要一個substr的最大值,那麼你會有點卡住。 –

回答

1

在您的具體使用情況,而不是在一個匿名,因爲你是一個類型中做這真的很酷的想法
塊或存儲過程,你可以user_type_attrs視圖得到的信息:

create or replace type t42 as object (
    id number 
) not final; 
/

create or replace type t42_sub under t42 (
    value varchar2(8), 
    constructor function t42_sub(p_value in varchar2) return self as result, 
    member function get_value return varchar2 
); 
/

create or replace type body t42_sub as 
    constructor function t42_sub(p_value in varchar2) return self as result is 
    begin 
    value := p_value; 
    return; 
    end t42_sub; 

    member function get_value return varchar2 is 
    l_attr_len number; 
    begin 
    select length into l_attr_len 
    from user_type_attrs 
    where type_name = 'T42_SUB' 
    and attr_name = 'VALUE'; 

    return case when self.value is null then lpad(' ', l_attr_len, ' ') 
     else rpad(self.value, l_attr_len, ' ') end; 
    end get_value; 
end; 
/

,然後使用該類型給出:

with t as (
    select t42_sub('AA').get_value() as val from dual 
    union all select t42_sub(null).get_value() as val from dual 
) 
select val, '<'|| val ||'>', length(val) 
from t; 

VAL    '<'||VAL||'>' LENGTH(VAL) 
--------------- --------------- ----------- 
AA    <AA  >    8 
       <  >    8 

顯然你可以編寫一個函數來獲取type/attr_name的長度,而不是在每個成員函數中重複select。

雖然我懷疑它會很貴,除非你能想出一個緩存機制。如果對象是長壽命,你可以做在構造函數中查找我想:

create or replace type t42_sub under t42 (
    value varchar2(8), 
    max_value_len number, 
    constructor function t42_sub(p_value in varchar2) return self as result, 
    member function get_value return varchar2 
); 
/

create or replace type body t42_sub as 
    constructor function t42_sub(p_value in varchar2) return self as result is 
    begin 
    value := p_value; 

    select length into max_value_len 
    from user_type_attrs 
    where type_name = 'T42_SUB' 
    and attr_name = 'VALUE'; 
    return; 
    end t42_sub; 

    member function get_value return varchar2 is 
    begin 
    return case when self.value is null then lpad(' ', max_value_len, ' ') 
     else rpad(self.value, max_value_len, ' ') end; 
    end get_value; 
end; 
/

但它似乎仍然喜歡的事,你應該在源頭控制,而不是在運行時處理,無論是在明確設定max_value_len := 8類型聲明(在value旁邊,所以您希望注意到它們都需要更改),或者使用使用替換變量的創建腳本。

+0

非常好......謝謝 – mlwacosmos

10

%TYPE屬性亞歷克斯·普爾建議的做法是從最佳實踐...只是FYI我提供VARCHAR2變量的例子:

create or replace function f_declared_length (
    p in out varchar2 
    ) 
    return integer 
    is 
    r integer; 
    a varchar2(32767) := p; 
    function f_c (p in out char) return integer is 
    begin 
     return length(p); 
    end; 
    begin 
    p := 1; 
    r := f_c(p); 
    p := a; 
    return r; 
    end; 
/

現在讓我們來測試這個功能:

set serveroutput on 
declare 
    v1 varchar2(23331); 
    v2 varchar2(500); 
    v3 varchar2(10); 

begin 
    dbms_output.put_line (f_declared_length (v1)); 
    dbms_output.put_line (f_declared_length (v2)); 
    dbms_output.put_line (f_declared_length (v3)); 
end; 
/

anonymous block completed 
23331 
500 
10 

Here is an original code and an idea。它基於以下結論:Oracle在內部知道變量的長度,並在通過調用堆棧時明確將其值從VARCHAR2轉換爲CHAR。這些信息用於確定需要將多少空間附加到實際的VARCHAR2參數值。

+0

...我嘗試了參數'IN OUT NOCOPY',並且沒有在功能或性能上有明顯的區別.. – ShoeLace

+0

這太酷了! – pablomatico

2

suPPLer(鼓掌)只是爲了好玩看看我的樣子)))

declare 
    l_var varchar2(10); 
begin 
    for i in 1 .. 32767 loop 
     begin 
      l_var := l_var || '*'; 
     exception 
      when others then 
       dbms_output.put_line('max length for l_var is ' || to_char(i - 1)); 
       exit; 
     end; 
    end loop; 
end; 
+0

有趣..但是,正如你所建議的..只是爲了好玩......不是爲了實際的代碼,因爲我預計它會明顯慢於'''f_declared_length'''。 – ShoeLace

相關問題