Anuncios en tutorial de programación PLSQL

jueves, 16 de junio de 2022

Los tipos de dato CHAR, VARCHAR2 y CLOB (Cadenas de caracteres en PL/SQL)

Después de haber hablado de los tipos numérico y de fecha del PL/SQL, llega el turno de empezar con las cadenas de caracteres. Lo primero que hay que saber al respecto es que una cadena de caracteres es una secuencia de símbolos pertenecientes a un conjunto particular de caracteres. En otras palabras, una cadena de caracteres puede estar compuesta por las letras del abecedario español, pero también podría estar compuesta por un conjunto de caracteres chinos o japoneses.

Tipos de dato CHAR, VARCHAR2 y CLOB

En PL/SQL existe tres tipos de cadenas de caracteres:

  • De longitud fija: de manera que la cadena de caracteres se rellena con espacios en blanco si su longitud es menor que la declarada.
  • De longitud variable: al definir la variable se declara la longitud máxima que puede alcanzar pero no se rellena con espacios si la longitud de la cadena es menor que la declarada. La máxima longitud de una variable de este tipo es de 32,767 caracteres.
  • Objetos CLOB (Character Large Objects): se trata de un tipo especial del PLSQL que permite almacenar cadenas de caracteres de longitud variable de hasta 128 terabytes.

Cadenas de caracteres literales

Las cadenas de caracteres literales empiezan y terminan con una comilla simple (‘).

-- Para almacenar la cadena Cadena literal l_cadena := 'Cadena literal';

Si por cualquier causa necesitáramos incluir una comilla simple dentro de una cadena de caracteres, basta con teclear dos veces de forma consecutiva dicha comilla simple, es decir:

-- Para almacenar la cadena Cadena ‘literal’ l_cadena := 'Cadena ''literal''';

También es posible utilizar el carácter “q” para definir un carácter alternativo de empiece y terminación de la cadena de caracteres literal.

-- Otra forma de almacenar la cadena Cadena ‘literal’ l_cadena := q'%Cadena 'literal'%';

Declaración de variables de tipo carácter

Una variable de tipo carácter se trata de un identificador que se declara como de tipo carácter y al que se le asigna un valor que podría ser un literal o una expresión. Para trabajar con este tipo de variables dentro de un programa PL/SQL es necesario declararlas, asignándoles uno de los datos de tipo carácter que se pueden manejar en las bases de datos Oracle (CHAR, NCHAR, VARCHAR2, NVARCHAR2, CLOB o NCLOB).

Los tipos de datos que empiezan con una “N”, son tipos de dato conocidos como del “conjunto nacional de caracteres”, lo que significa que se utilizan para almacenar datos carácter que siguen el estándar Unicode (Unicode es un estándar de codificación de caracteres que permite almacenar información de cualquier lengua utilizando un único conjunto de caracteres).

A la hora de declarar una variable de tipo carácter de longitud variable, es necesario indicar la longitud máxima de la misma, es decir, el máximo número de caracteres que podrá contener. En el siguiente ejemplo vemos como se definiría una variable utilizando el tipo de dato VARCHAR2 que como mucho podría tener una longitud de 50 caracteres:

DECLARE l_cadena VARCHAR2(50);

Si no se indica la longitud máxima de una variable VARCHAR2, la base de datos Oracle genera un error de compilación como podemos ver a continuación:

SQL> DECLARE 2 l_cadena VARCHAR2; 3 BEGIN 4 l_cadena := 'Cadena literal'; 5 END; 6 / l_cadena VARCHAR2; * ERROR en línea 2: ORA-06550: línea 2, columna 10: PLS-00215: Las restricciones de longitud de cadena deben estar en el rango (1 .. 32767)

Para declarar una variable de tipo carácter de longitud fija se utiliza el tipo de dato de la base de datos Oracle CHAR:

DECLARE l_long_fija CHAR(4) := 'Fija';

Con el tipo de dato CHAR no es necesario especificar la máxima longitud de la cadena. Si no especificamos dicha longitud, la base de datos asignará a nuestra variable la longitud de la cadena que asignemos en la cláusula DECLARE de nuestro programa PLSQL. Si no asignamos ningún valor a la variable, entonces tendrá por defecto la longitud máxima de 1.

DECLARE l_long_fija1 CHAR(4) := 'Fija'; l_long_fija2 CHAR := 'Fija'; l_long_fija3 CHAR;

En el ejemplo las declaraciones de las variables carácter l_long_fija1 y l_long_fija2 son idénticas, la longitud máxima que podrán almacenar dichas variable será 4; por el contrario, la máxima longitud que podrá almacenar la variable carácter l_long_fija3 será 1. Veámoslo:

SQL> DECLARE 2 l_long_fija2 CHAR := 'Fija'; 3 BEGIN 4 l_long_fija2 := 'Cinco'; 5 END; 6 / DECLARE * ERROR en línea 1: ORA-06502: PL/SQL: error : buffer de cadenas de caracteres demasiado pequeño numérico o de valor ORA-06512: en línea 2 SQL> DECLARE 2 l_long_fija3 CHAR; 3 BEGIN 4 l_long_fija3 := 'es'; 5 END; 6 / DECLARE * ERROR en línea 1: ORA-06502: PL/SQL: error : buffer de cadenas de caracteres demasiado pequeño numérico o de valor ORA-06512: en línea 4

Para terminar con las variables de tipo CHAR, conviene saber que si definimos una variable de este tipo con una longitud superior a 1, la base de datos Oracle, independientemente de la longitud de la cadena que realmente le asignemos, rellenará dicha cadena con espacios en blanco hasta completar la longitud máxima asignada.

Finalmente, si necesitamos utilizar una variable de tipo carácter muy larga, entonces deberemos utilizar el tipo de dato CLOB. Para este tipo de dato no es necesario asignar una longitud máxima, ya que dicha longitud la determinará automáticamente la base de datos Oracle utilizando como base el tamaño mínimo de los bloques de almacenamiento de la base de datos.

DECLARE l_cadena_larga CLOB;

¿Qué tipo de dato carácter utilizar en PL/SQL?

A continuación os dejo una pequeña guía, así como una lista de recomendaciones que deberéis tener en cuenta a la hora de seleccionar que tipo de dato carácter utilizar en un programa PLSQL:

  • Si la cadena de cadena de caracteres puede contener más de 32.767 caracteres, entonces deberemos utilizar el tipo CLOB (o NCLOB).
  • Si el valor asignado a la cadena de caracteres siempre tiene la misma longitud, como puede ser el caso del código de identificación fiscal de una empresa, entonces lo recomendable es utilizar el tipo CHAR (o NCHAR).
  • En cualquier otro caso, y por lo tanto en la mayoría de las ocasiones, lo recomendable es utilizar el tipo VARCHAR2 (o NVARCHAR2).

A lo largo de mi experiencia profesional me he encontrado con piezas de código PL/SQL que invariablemente utilizaban el tipo de dato CHAR. Codificando de esta manera podemos encontrarnos con alguna que otra sorpresa como podemos ver en el siguiente ejemplo, en el que vamos a mezclar una variable tipo CHAR con otra tipo VARCHAR2:

DECLARE l_varchar2 VARCHAR2 (10) := 'Cinco'; l_char CHAR (10) := 'Cinco'; BEGIN IF l_varchar2 = l_char THEN DBMS_OUTPUT.put_line ('Son iguales'); ELSE DBMS_OUTPUT.put_line ('Son distintas'); END IF; END;

Viendo el código parece que lo lógico sería que nuestro programa PLSQL, después de su ejecución, mostrase las palabras Son iguales, pero esto no es lo que ocurre, en su lugar veremos como aparece Son distintas. El motivo es que a la variable l_char, la base de datos Oracle le ha añadido un total de 5 espacios en blanco hasta completar la longitud de 10.

En conclusión, debemos ser muy cuidadosos a la hora de utilizar el tipo de dato CHAR, ya lo utilicemos para una variable en un programa PL/SQL, para un parámetro en un procedimiento o función, o para una columna de una tabla de la base de datos Oracle.

Artículos relacionados:
Operaciones aritméticas con fechas y la función TRUNC del PL/SQL.
Tipos de datos en PLSQL.

4 comentarios:

iblazquez dijo...

Hola Jose Luis, antes de nada decirte que soy un asiduo de tu blog, me parece interesantísimo y no dejo de aprender cosas.

Estoy intentando optimizar una query muy simple y no entiendo el comportamiento de de oracle. No se si tienes algun buzón donde pueda enviartela.

Un saludo.

JLPM dijo...

Hola IBlazquez,

Puedes dirigirte a mi en este email pepelublog[arroba]gmail[punto]com.

Celeste Click dijo...

IF l_varchar2 = l_fija THEN
--La línea debería ser:
IF l_varchar2 = l_char THEN

Gracias por el blog, muy bueno.

JLPM dijo...

Gracias Unknown. Ya está corregido.