2009-11-25 30 views
27

¿Cómo obtengo el tamaño en bytes de una columna CLOB en Oracle?¿Cómo obtener el tamaño en bytes de una columna CLOB en Oracle?

LENGTH() y DBMS_LOB.getLength() devuelven el número de caracteres utilizados en el CLOB pero necesito saber cuántos bytes se utilizan (estoy tratando con conjuntos de caracteres multibyte).

+0

¿Por qué le preocupa el tamaño en bytes del CLOB? – Thanatos

+1

No es el OP, pero en mi caso estaba recuperando CLOBS en un enlace de base de datos y tuve que cortarlos en fragmentos de 4000 bytes, y quería saber cuántos fragmentos necesitaba para mis datos. –

+0

esto es una locura, quiero exprimir chino clob en varchar2 y no puedo hacerlo porque no puedo determinar el tamaño – Toolkit

Respuesta

13

Después de pensarlo se me ocurrió con esta solución:

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

SUBSTR sólo devuelve los primeros 4000 caracteres (tamaño de la cadena max)

TO_CHAR conversos CLOB-VARCHAR2

LENGTHB devuelve el longitud en Bytes utilizada por la cadena.

+14

Pero esto solo funciona si tu CLOB es pequeño. –

+1

Podría decir 'LENGTHB (TO_CHAR (DBMS_LOB.SUBSTR (, 3000,1))) + NVL (LENGTHB (TO_CHAR (DBMS_LOB.SUBSTR (, 3000,3001))), 0)' - esto funciona hasta 6000 bytes, pero podría extenderse indefinidamente. Si está tratando con conjuntos de caracteres de varios bytes, necesita subserver a menos de 4000 caracteres, o obtendrá un buffer de cadena de caracteres ORA-06501 demasiado pequeño. También tenga en cuenta que DBMS_LOB.SUBSTR ordena de forma inversa la cantidad y los parámetros de compensación. –

+0

Véase también http://stackoverflow.com/questions/10331912/performance-of-substr-on-clob – gavenkoa

-2

sólo funciona hasta 4000 bytes, ¿Y si el CLOB es más grande que 4000 bytes entonces usamos esta

declare 
v_clob_size clob; 

begin 

     v_clob_size:= (DBMS_LOB.getlength(v_clob))/1024/1024; 
     DBMS_OUTPUT.put_line('CLOB Size ' || v_clob_size); 
end; 

o

select (DBMS_LOB.getlength(your_column_name))/1024/1024 from your_table 
+0

¿Pero DMBS_LOG.getlength (...) no devuelve el número de caracteres en lugar de los bytes? –

+0

ya indicó que DBMS_LOB.getlength era inapropiado para sus necesidades ... – Reimius

10

estoy añadiendo mi comentario como respuesta porque resuelve el problema original para una gama más amplia de casos que la respuesta aceptada. Nota: aún debe conocer la longitud máxima y la proporción aproximada de caracteres de varios bytes que tendrán sus datos.

Si tiene un CLOB mayor que 4000 bytes, necesita usar DBMS_LOB.SUBSTR en lugar de SUBSTR. Tenga en cuenta que los parámetros cantidad y offset se invierten en DBMS_LOB.SUBSTR.

A continuación, puede que necesite subcadena una cantidad inferior a 4000, ya que este parámetro es el número de caracteres, y si usted tiene caracteres de múltiples bytes entonces 4000 caracteres será de más de 4000 bytes larga, y obtendrás ORA-06502: PL/SQL: numeric or value error: character string buffer too small porque el resultado de la subcadena necesita caber en un VARCHAR2 que tiene un límite de 4000 bytes. La cantidad exacta de caracteres que puede recuperar depende del número promedio de bytes por carácter en sus datos.

Así que mi respuesta es:

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) 
+... 

donde puede añadir tantos trozos como sea necesario para cubrir su CLOB más larga, y ajustar el tamaño del trozo de acuerdo con bytes-per-carácter de sus datos promedio.

+0

Consulte la respuesta de TobiK para la misma técnica expresada como un bucle, para que no tenga que comprobar si ha agregado suficientes fragmentos para cubrir su CLOB más grande . –

+0

¿Entonces esta solución depende de la esperanza y las conjeturas para evitar los errores de ORA-06502? ¡Seguramente hay una forma robusta de dividir un CLOB en fragmentos de tamaño VARCHAR2! – PhilHibbs

+0

@PhilHibbs Es suficiente para mi propósito porque solo tengo que tratar con el francés y puedo hacer suposiciones sobre la proporción de caracteres multibyte. Pero estoy de acuerdo en que no es satisfactorio y estaría encantado de ver una mejor respuesta. –

4

prueba este CLOB para los tamaños más grandes que VARCHAR2:

Tenemos que dividir el CLOB en partes de tamaños "compatibles", VARCHAR2 lengthb correr a través de cada parte de los datos CLOB, y resumir los resultados.

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

Esto es mejor que mi respuesta si necesita que la solicitud sea ejecutable en el futuro sin conocimiento * a priori * del tamaño CLOB máximo posible. Sin embargo, lo escribiría como una función en ese caso. –

3

NVL (longitud (clob_col_name), 0) funciona para mí.

+0

No, 'length' devuelve la longitud en * caracteres *, no en bytes. –

1

Compruebe el nombre del segmento LOB de dba_lobs utilizando el nombre de la tabla.

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

Ahora use el nombre del segmento para buscar los bytes utilizados en 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; 
0

La solución simple es convertir CLOB en BLOB y luego solicitar la longitud de BLOB!

El problema es que Oracle no tiene una función que echó a CLOB BLOB, pero simplemente puede definir una función para hacer que

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; 

El comando SQL a utilizar para obtener el número de bytes es

SELECT length(clob2blob(fieldname)) as nr_bytes 

o

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

he probado esto en Oracle 10g sin utilizar Unico de (UTF-8). pero creo que esta solución debe ser correcto uso de Unicode (UTF-8) instancia de Oracle :-)

Quiero dar gracias a Nashev que ha publicado una solución para convertir CLOB to blob How convert CLOB to BLOB in Oracle? y con este post escrito en alemán (el código está en PL/SQL) 13ter.info.blog que da adicionalmente una función para convertir blob en clob!

¿Alguien puede probar los 2 comandos en CLOB Unicode (UTF-8) así que estoy seguro de que esto funciona con Unicode?

Cuestiones relacionadas