2013-07-17 4 views
7

変数の最大長を与える関数がplsqlに存在するかどうか疑問に思っていました。例えば変数の最大長を得ることは可能ですか

ヴァリアーがnullであっても、私は

DECLARE 

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

を宣言した場合、私はvarchar型の長さは7を得ることができます。

--- exemple

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

変数を宣言できますか(そしてコードの他の部分も、別の変数と見なします)テーブルの中で;例えば'varia 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 

明らかに、各メンバー関数でselectを繰り返すのではなく、/ attr_name型の長さを取得する関数を書くことができます。

キャッシングの仕組みを考え出すことができない限り、かなり高額になると思われます。オブジェクトは長寿命であれば、あなたは、コンストラクタでのルックアップを行うことができ、私は考えます:

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

はとてもクールです...私はパラメータを '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

関連する問題