2013-07-17 12 views
7

Zastanawiam się, czy w plsql istnieje funkcja podająca maksymalną długość zmiennej.Czy jest możliwe uzyskanie maksymalnej możliwej długości zmiennej

Na przykład, jeśli Oświadczam

DECLARE 

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

chociaż varia jest null, mogę dostać długość 7 z varchar.

--- 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; 

Więc zastanawiałem się, czy to prosta funkcja istniała aby uzyskać rozmiar pola więc nie trzeba używać liczb w pobierające: jeśli rozmiar pola ulega zmianie , nie byłoby potrzeby zmiany pobierające, byłoby wypracować bez względu na wielkość varchar

ale rozumiem, że nie jest możliwe

Dziękuję wszystkim

+0

To dziwny wymóg. Rozmiar jest właśnie tam, dlaczego potrzebujesz wywołania funkcji? – Mat

+0

ponieważ, jeśli pewnego dnia zmieni się rozmiar, jest inna część kodu, która nie musi być zmieniona – mlwacosmos

+2

Czy możesz zadeklarować zmienną (i drugą część kodu, która, jak zakładam, jest również inną zmienną) na podstawie kolumny w tabeli; na przykład 'zadeklarować varia tab.col% TYPE'? Wtedy wszystkie odniesienia zostałyby zmienione, gdyby definicja tabeli uległa zmianie. Zależy od tego, jak go używasz - jeśli potrzebujesz maksymalnej wartości dla substr, np. Przy wypełnianiu, wtedy utkniesz. –

Odpowiedz

1

W Twoim konkretnym przypadku zastosowania, ponieważ robisz to w ramach typu, a nie w anonimowym blok lub procedura przechowywana, można uzyskać informacje z widoku 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; 
/

A następnie przy użyciu tego typu daje:

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 

Oczywiście można napisać funkcję, aby uzyskać długość dla typu/attr_name, zamiast powtarzać wybór w każdej funkcji składowej.

Podejrzewam, że będzie to dość kosztowne, chyba że można wymyślić mechanizm buforowania. Jeśli obiekty są długowieczne można zrobić przeglądowej w konstruktorze Przypuszczam:

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; 
/

Ale nadal wydaje się jak coś powinno być zachowanie podczas kontroli źródła aniżeli w czasie wykonywania, albo jawnie ustawienie max_value_len := 8 w deklaracja typu (obok value, więc miejmy nadzieję, że obaj muszą zostać zmienione) lub ze skryptem tworzenia, który wykorzystuje zmienne podstawiania.

+0

To jest doskonałe ... dziękuję – mlwacosmos

10

Podejście z atrybutem %TYPE Alex Poole sugerowane jest jednym z najlepszych praktyk ... ale ja po prostu FYI stanowić przykład dla zmiennej 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; 
/

Teraz przetestować tę funkcję:

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. Opiera się na konkluzji, że Oracle wewnętrznie zna długość zmiennej, gdy konwertuje jej wartość z VARCHAR2 na CHAR jawnie przechodząc przez stos wywołań. Takie informacje służą do określenia, ile spacji należy dodać do rzeczywistej wartości parametru VARCHAR2.

+0

, który jest bardzo fajny ... Próbowałem dokonać parametru "IN OUT NOCOPY" i nie było widoczna różnica w funkcji lub wydajności .. – ShoeLace

+0

to jest takie fajne! – pablomatico

2

napięta (klaśnięcie) naprawdę fajny pomysł
tylko na wygląd zabawy na drodze)))

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

interesujące .. ale jak sugerujesz .. tylko dla zabawy .. nie dla rzeczywistego kodu, ponieważ spodziewam się, że będzie znacznie wolniej niż "f_deklarowana_długość". – ShoeLace

Powiązane problemy