Oracle 是否可以获得变量的最大可能长度

Oracle 是否可以获得变量的最大可能长度,oracle,plsql,Oracle,Plsql,我想知道plsql中是否存在给出变量最大长度的函数 例如,如果我声明 DECLARE varia VARCHAR2(7) BEGIN call of a function that would return 7 END 即使varia为null,我也可以得到varchar的长度7 ---例 create or replace TYPE ENREG_320_03 UNDER ENREG_320_BASE( date_creation VARCHAR2(8), raison_social

我想知道plsql中是否存在给出变量最大长度的函数

例如,如果我声明

DECLARE

varia VARCHAR2(7)
BEGIN
   call of a function that would return 7
END
即使varia为null,我也可以得到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;
所以我想知道是否存在一个简单的函数来获取字段的大小,这样我就不必在getter中使用数字:如果字段的大小改变了,就不需要改变getter,它将计算出varchar的大小

但我明白这是不可能的


谢谢大家

Alex Poole建议的具有
%TYPE
属性的方法是最佳实践中的一种。。。但仅供参考,我为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
。这是基于这样一个结论:Oracle在遍历调用堆栈时,在显式地将变量的值从VARCHAR2转换为CHAR时,内部知道变量的长度。这些信息用于决定实际的VARCHAR2参数值需要附加多少空格。

suPPLer(clap)真是个好主意
只是为了好玩看看我的方式)


在您的特定用例中,由于您是在类型中而不是在匿名块或存储过程中执行此操作,因此可以从
user\u type\u 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 

但这似乎仍然是您应该在源代码管理中而不是在运行时处理的事情,或者在类型声明中显式地设置
max\u value\u len:=8
(在
值旁边,所以您希望注意到它们都需要更改),或者使用使用替换变量的创建脚本。

这是一种奇怪的要求。大小就在那里,为什么需要函数调用呢?因为,如果有一天大小改变了,代码的另一部分就不需要改变了。您可以根据表中的一列声明变量(以及代码的另一部分,我假设它也是另一个变量);e、 g.
声明变量选项卡列%TYPE
?然后,如果表定义更改,所有引用都将更改。当然,这取决于您如何使用它-例如,如果您在填充时需要substr的最大值,那么您可能会有点卡住。此外,这是一个匿名块(看起来是),您是如何运行它的?如果它来自SLQ*Plus,那么您可以使用替换变量来设置大小,并且仍然可以在同一脚本中使用该变量供以后使用。还需要更多的背景知识……恐怕PL/SQL中没有内省功能。有USER_IDENTIFIERS视图,但根据我的经验,它A)没有为大多数代码填充,B)无论如何都不包含所需的信息。我同意@AlexPoole关于尽可能使用列的%类型的评论。另一种可能是将变量声明为VARCHAR2(32767)(最大可能大小),然后就不用担心了。。。我试着使用参数“IN-OUT NOCOPY”,但在功能或性能上没有明显的差异..很有趣。。但正如你所建议的。。只是为了好玩。。不适用于实际代码,因为我预计它将比
f_声明的长度
慢得多。
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 
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;
/