sábado, 26 de julio de 2008

ORA-01440: column to be modified must be empty to decrease precision or scale

ALTER TABLE t1 MODIFY (nr_pct NUMBER(5,2))
ORA-01440: column to be modified must be empty to decrease precision or scale
¿Cómo disminuir la longitud de una columna con datos y evitar el error?

Para este ejemplo, vamos a agregar una dificultad extra: la columna que queremos alterar es NOT NULL.

Presento dos formas de hacer esto con SQL*Plus:


FORMA 1: VACIANDO Y ALTERANDO


Respaldar la columna
CREATE TABLE t1_backup AS SELECT id, nr_pct FROM t1;
Setear la columna como NULL
ALTER TABLE t1 MODIFY (nr_pct NULL);
Vaciar la columna
UPDATE t1 SET nr_pct=NULL;
Ajustar el tamaño deseado de la columna
ALTER TABLE t1 MODIFY (nr_pct NUMBER(5,2));
Cargar los datos a la columna
UPDATE t1 SET nr_pct=(SELECT nr_pct FROM t1_backup WHERE t1_backup.id=t1.id);
Alterar la columna como NOT NULL nuevamente
ALTER TABLE t1 MODIFY (nr_pct NOT NULL);

Ventajas: Se preserva el orden de las columnas dentro de la tabla
Desventajas: Poco performante para tablas muy grandes (millones de datos), requiere crear un índice en la tabla t1_backup para mejorar la performance


FORMA 2: AGREGANDO COLUMNA EXTRA

Agregar una columna a la tabla con el tamaño deseado
ALTER TABLE t1 ADD (nr_pct_2 NUMBER(5,2) NOT NULL);
Cargar la nueva columna con los datos
UPDATE t1 SET nr_pct_2=nr_pct;
Eliminar la columna original
ALTER TABLE t1 DROP COLUMN nr_pct;
Renombrar la nueva columna al nombre de la original
ALTER TABLE t1 RENAME COLUMN nr_pct_2 TO nr_pct;

Ventajas: Más performante que la forma 1 para tablas grandes. Más fácil de realizar.
Desventajas: Sólo aplicable a 9i o superiores (8i no posibilita el renombrado de columnas).
La columna alterada quedará al final de la tabla si hacemos un DESC.

martes, 8 de julio de 2008

Cómo obtener la fecha de ayer en Unix

Esta es una tarea sencilla en Linux. Para obtener el día anterior simplemente usamos la función date:
date --date='1 day ago'
Esta funcionalidad tiene varias formas que flexibilizan la tarea de obtener una fecha relativa del pasado o futuro. Sólo basta dar una mirada a la documentación del man.

El problema ocurre si usamos Sun Solaris: este sistema operativo no tiene una modalidad similar para date. Es frustrante para un programador casual como yo, que algo tan sencillo no esté implementado en el sistema operativo.
He visto algunos foros en la web donde se pueden encontrar diversos Shell scripts para calcular el día anterior dependiendo de si el mes tiene 30 o 31 dias, si es febrero, si es año bisiesto... y la verdad que la idea de tanta complejidad para algo tan simple no me satisface.

Una solución directa y fácil de obtener el dia anterior en Solaris es la siguiente: agendar en el programa crontab (o scheduler unix de preferencia) a las 23:59, un simple script que escriba la hora actual en un archivo:
#/bin/ksh
date > ayer.txt

Listo!
Ahora nuestros scripts pueden acceder en forma simple a la fecha de ayer.

Vea también:
Limpieza de archivos en Unix
Comandos útiles para Unix Shell
Cómo verificar archivos y directorios en Shell

miércoles, 2 de julio de 2008

Obtener la versión de la base desde PL/SQL

Si queremos obtener cual es la versión de la base de datos para hacer una u otra cosa, podemos utilizar el paquete dbms_utility y el procedimiento db_version. El mismo nos retorna un string del tipo 9.2.0.4, el cual podemos consultar para programar a conveniencia.
  dbms_utility.db_version(v_version, v_compatible);
Una observación: cuidado con utilizar comandos que no existan en otras versiones, para eso está la compilación condicional introducida en Oracle 9i R2. Esta es una simple función que nos retorna la versión de la base actual que nos puede servir por ejemplo para reconstruir nombres de archivos que dependan de la versión utilizada.

El siguiente bloque PL/SQL es un ejemplo de como puede utilizarse db_version para condicionar la programación.

DECLARE
v_version varchar2 (32);
v_compatible varchar2 (32);
BEGIN
dbms_utility.db_version(v_version, v_compatible);

if substr(v_version,1,2) = '10' then
...
elsif substr(v_version,1,1) = '9' then
...
elsif substr(v_version,1,3) = '8.1' then
...
elsif substr(v_version,1,3) = '8.0' then
...
elsif substr(v_version,1,1) = '7' then
...
end if;

...

END;
Ver también:
Compilación condicional en 9i