2012-08-23 19 views
7

Los caracteres de varios bytes me han causado mucho dolor.SELECCIONE la mayor cantidad posible de datos de CLOB a VARCHAR2, con caracteres de varios bytes en los datos

¿Alguna sugerencia para este problema?

Tengo un campo CLOB que fuerza contiene algunos caracteres multi-byte, y necesito para seleccionar en SQL y convertir este campo en una cadena de proceso aguas abajo, Actualmente estoy usando:

SELECT DBMS_LOB.SUBSTR(description, 4000, 1) FROM table 

Pero el comando 4000 in above tiene la longitud de caracteres, en lugar de bytes. Así que tuve que cambiar a 3000 para manejar cualquier carácter de varios bytes que pudiera haberse infiltrado en los datos, de lo contrario se produciría un error en el tamaño del buffer.

El problema es que para los registros que no contienen caracteres multibyte, podría truncar innecesariamente más datos de los necesarios. (. El 4000 es la limitación de cuerdas, podemos/tuvimos que vivir con eso)

¿Hay una manera de hacer algo equivalente a:

SELECT DBMS_LOB.SUBSTR(description, 4000bytes, 1) FROM table 

De esa manera puedo obtener la mayor cantidad de datos a cabo como sea posible.

Nota: No se me permite crear tablas temporales/puntos de vista, no usar PL/SQL, solamente SQL SELECT ...

Respuesta

4

truncar Tal vez el varchar2 resultante con SUBSTR:

SELECT SUBSTRB(DBMS_LOB.SUBSTR(description, 4000, 1), 1, 4000) FROM table 
+0

¿No debería ser "... con SUBSTRB"? (SUBSTRB en lugar de SUBSTR) –

+1

Fuera de interés: ¿Sabe qué sucede si los primeros 3999 caracteres tienen un byte de longitud y el 4000th es de varios bytes? ¿No devolverá un carácter incorrecto en la posición 4000 (ya que interpreta el primer byte del carácter de varios bytes como un carácter de byte único)? –

+2

No Jeffery no funcionará, si 'descripción' contiene caracteres multibyte, el DBMS_LOB.SUBSTR más interno ya golpea un error de búfer de cadena antes de llegar al SUBSTRB. – alchn

7

pensamiento de Jeffrey proceso está bien, pero alchn también es correcto. Acabo de toparme con este mismo problema y esta es mi solución. Tendrá que ser capaz de crear una función sin embargo:

Create Or Replace Function clob_substr(p_clob In Clob 
             ,p_offset In Pls_Integer 
             ,p_length In Pls_Integer) Return Varchar2 Is 
Begin 
    Return substrb(dbms_lob.substr(p_clob 
           ,p_length 
           ,p_offset) 
       ,1 
       ,p_length); 
End; 
/

Aquí es una demostración de su uso:

Select c 
     ,clob_substr(c 
        ,1 
        ,4000) 
    From (

     Select xmlelement("t", rpad('é', 4000, 'é'), rpad('é', 4000, 'é')).extract('//text()').getclobval() c 
      From dual 

     ); 
+1

He creado un ejemplo completo (¡espero!) Basado en esta respuesta en https://bitbucket.org/janihur/orasql-ex/src/tip/clob-2.sql – user272735

+0

He probado y confirmado que al usar esta función funciona mejor que la solución de Jeffrey. Sin embargo, no entiendo por qué. ¿No está haciendo esto exactamente lo mismo, pero en una función en lugar de en línea? ¿Por qué hace una diferencia aquí? – KStensland

+0

Sospecho que la diferencia es que varchar2 en PL/SQL puede llegar a 32.767 bytes, mientras que en SQL (al menos en 11g y anteriores) el máximo es de 4.000 bytes. –

Cuestiones relacionadas