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).
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.
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(DBMS_LOB.SUBSTR(<CLOB-Column>,3000,3001))),0)
+NVL(LENGTHB(TO_CHAR(DBMS_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.
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;
/
NVL (length (clob_col_name), 0) fonctionne pour moi.
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?
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;