web-dev-qa-db-fra.com

Comment obtenir la taille en octets d'une colonne CLOB dans Oracle?

Comment obtenir la taille en octets d'une colonne CLOB dans Oracle?

LENGTH() et DBMS_LOB.getLength() renvoient tous les deux le nombre de caractères utilisés dans le CLOB mais j'ai besoin de savoir combien d'octets sont utilisés (j'ai affaire à des jeux de caractères multi-octets).

32
rag

Après réflexion, j'ai trouvé cette solution:

 LENGTHB(TO_CHAR(SUBSTR(<CLOB-Column>,1,4000)))

SUBSTR renvoie uniquement les 4000 premiers caractères (taille de chaîne maximale)

TO_CHAR convertit de CLOB en VARCHAR2

LENGTHB renvoie la longueur en octets utilisée par la chaîne.

17
rag

J'ajoute mon commentaire en tant que réponse car il résout le problème d'origine pour un éventail de cas plus large que la réponse acceptée. Remarque: vous devez toujours connaître la longueur maximale et la proportion approximative de caractères multi-octets que vos données auront.

Si vous avez un CLOB supérieur à 4000 octets, vous devez utiliser DBMS_LOB.SUBSTR plutôt que SUBSTR. Notez que les paramètres quantité et offset sont inversés dans DBMS_LOB.SUBSTR.

Ensuite, vous devrez peut-être sous-chaîne un montant inférieur à 4000, car ce paramètre est le nombre de caractères , et si vous avez des caractères multi-octets, alors 4000 les caractères feront plus de 4000 octets de long, et vous obtiendrez ORA-06502: PL/SQL: numeric or value error: character string buffer too small car le résultat de la sous-chaîne doit tenir dans un VARCHAR2 qui a une limite de 4000 octets. Le nombre exact de caractères que vous pouvez récupérer dépend du nombre moyen d'octets par caractère dans vos données.

Donc ma réponse est:

LENGTHB(TO_CHAR(DBMS_LOB.SUBSTR(<CLOB-Column>,3000,1)))
+NVL(LENGTHB(TO_CHAR(DBM‌​S_LOB.SUBSTR(<CLOB-Column>,3000,3001))),0)
+NVL(LENGTHB(TO_CHAR(DBM‌​S_LOB.SUBSTR(<CLOB-Column>,6000,6001))),0)
+...

où vous ajoutez autant de morceaux que nécessaire pour couvrir votre CLOB le plus long et ajustez la taille des morceaux en fonction du nombre moyen d'octets par caractère de vos données.

16
Andrew Spencer

Essayez celui-ci pour des tailles CLOB plus grandes que VARCHAR2:

Nous devons diviser le CLOB en parties de tailles "compatibles VARCHAR2", exécuter longueurb dans chaque partie des données CLOB et résumer tous les résultats.

declare
   my_sum int;
begin
   for x in ( select COLUMN, ceil(DBMS_LOB.getlength(COLUMN) / 2000) steps from TABLE ) 
   loop
       my_sum := 0;
       for y in 1 .. x.steps
       loop
          my_sum := my_sum + lengthb(dbms_lob.substr( x.COLUMN, 2000, (y-1)*2000+1 ));
          -- some additional output
          dbms_output.put_line('step:' || y );
          dbms_output.put_line('char length:' || DBMS_LOB.getlength(dbms_lob.substr( x.COLUMN, 2000 , (y-1)*2000+1 )));
          dbms_output.put_line('byte length:' || lengthb(dbms_lob.substr( x.COLUMN, 2000, (y-1)*2000+1 )));
          continue;
        end loop;
        dbms_output.put_line('char summary:' || DBMS_LOB.getlength(x.COLUMN));
        dbms_output.put_line('byte summary:' || my_sum);
        continue;
    end loop;
end;
/
6
TobiK

NVL (length (clob_col_name), 0) fonctionne pour moi.

5
user5534142

La solution simple consiste à convertir CLOB en BLOB puis à demander la longueur de BLOB!

Le problème est qu'Oracle n'a pas de fonction qui convertit CLOB en BLOB, mais nous pouvons simplement définir une fonction pour le faire

create or replace
FUNCTION clob2blob (p_in clob) RETURN blob IS 
    v_blob        blob;
    v_desc_offset PLS_INTEGER := 1;
    v_src_offset  PLS_INTEGER := 1;
    v_lang        PLS_INTEGER := 0;
    v_warning     PLS_INTEGER := 0;  
BEGIN
    dbms_lob.createtemporary(v_blob,TRUE);
    dbms_lob.converttoblob
        ( v_blob
        , p_in
        , dbms_lob.getlength(p_in)
        , v_desc_offset
        , v_src_offset
        , dbms_lob.default_csid
        , v_lang
        , v_warning
        );
    RETURN v_blob;
END;

La commande SQL à utiliser pour obtenir le nombre d'octets est

SELECT length(clob2blob(fieldname)) as nr_bytes 

ou

SELECT dbms_lob.getlength(clob2blob(fieldname)) as nr_bytes

J'ai testé cela sur Oracle 10g sans utiliser Unicode (UTF-8). Mais je pense que cette solution doit être correcte en utilisant l'instance Oracle Unicode (UTF-8) :-)

Je veux rendre grâce à Nashev qui a posté une solution pour convertir clob en blob Comment convertir CLOB en BLOB dans Oracle? et à cet article écrit en allemand (le code est en PL/SQL) 13ter.info.blog qui donne en plus une fonction pour convertir blob en clob!

Quelqu'un peut-il tester les 2 commandes dans Unicode (UTF-8) CLOB, donc je suis sûr que cela fonctionne avec Unicode?

4
schlebe

Vérifiez le nom du segment LOB dans dba_lobs en utilisant le nom de la table.

select TABLE_NAME,OWNER,COLUMN_NAME,SEGMENT_NAME from dba_lobs where TABLE_NAME='<<TABLE NAME>>';

Utilisez maintenant le nom du segment pour trouver les octets utilisés dans dba_segments.

select s.segment_name, s.partition_name, bytes/1048576 "Size (MB)"
from dba_segments s, dba_lobs l
where s.segment_name = l.segment_name
and s.owner = '<< OWNER >> ' order by s.segment_name, s.partition_name;
3
Nalla Krishna