¿Qué sucede cuando modifica (reduce) la longitud de una columna?

10

Digamos que tengo dos columnas de tipo NUMBER(sin precisión y escala) y VARCHAR(300). Vi que estas columnas son demasiado grandes para mis datos, por lo que quiero modificarlas en NUMBER(11)y VARCHAR(10). Entonces, si ejecuto esta declaración SQL:

ALTER TABLE FOO
    MODIFY(BAR NUMBER(10));
  • ¿Podré hacer eso en una columna no vacía?
  • Si es así, ¿qué sucede si hay un valor mayor que NUMBER(10), me lo contará Oracle?
  • ¿Los valores predeterminados de la columna permanecerán sin cambios si se definieron previamente?
  • ¿La opción anulable de columna permanecerá sin cambios?
  • ¿La clave primaria, externa y única de esa columna permanecerá sin cambios?
  • ¿Las restricciones que involucran esas columnas permanecerán sin cambios?
  • ¿Los índices en esas columnas permanecerán sin cambios?

¿Existe alguna documentación oficial que responda mis preguntas?

mnowotka
fuente

Respuestas:

12

La Guía del administrador de Oracle dice lo siguiente:

Use la instrucción ALTER TABLE ... MODIFY para modificar una definición de columna existente. Puede modificar el tipo de datos de columna, el valor predeterminado, la restricción de columna, la expresión de columna (para columnas virtuales) y el cifrado de columna.

Puede aumentar la longitud de una columna existente, o disminuirla, si todos los datos existentes satisfacen la nueva longitud. Puede cambiar una columna de semántica de bytes a semántica CHAR o viceversa. Debe establecer el parámetro de inicialización BLANK_TRIMMING = TRUE para disminuir la longitud de una columna CHAR no vacía.

Si está modificando una tabla para aumentar la longitud de una columna de tipo de datos CHAR, tenga en cuenta que esta puede ser una operación que requiere mucho tiempo y puede requerir un almacenamiento adicional sustancial, especialmente si la tabla contiene muchas filas. Esto se debe a que el valor CHAR en cada fila debe estar en blanco para satisfacer la nueva longitud de la columna.

La Referencia del lenguaje Oracle SQL tiene muchos más detalles, incluidos los siguientes:

Puede cambiar el tipo de datos de cualquier columna si todas las filas de la columna contienen valores nulos. Sin embargo, si cambia el tipo de datos de una columna en una tabla de contenedor de vista materializada, Oracle Database invalida la vista materializada correspondiente.

Siempre puede aumentar el tamaño de un carácter o columna sin formato o la precisión de una columna numérica, independientemente de si todas las filas contienen valores nulos. Puede reducir el tamaño de un tipo de datos de una columna siempre que el cambio no requiera modificar los datos. La base de datos escanea los datos existentes y devuelve un error si existen datos que exceden el nuevo límite de longitud.

Puede modificar una columna FECHA a TIMESTAMP o TIMESTAMP WITH LOCAL TIME ZONE. Puede modificar cualquier TIMESTAMP WITH LOCAL TIME ZONE a una columna DATE.

Si la tabla está vacía, puede aumentar o disminuir el campo inicial o el segundo valor fraccional de una columna de fecha y hora o intervalo. Si la tabla no está vacía, solo puede aumentar el campo inicial o el segundo fraccionario de una columna de fecha / hora o intervalo.

Para las columnas CHAR y VARCHAR2, puede cambiar la semántica de longitud especificando CHAR (para indicar la semántica de caracteres para una columna que se especificó originalmente en bytes) o BYTE (para indicar la semántica de bytes para una columna que se especificó originalmente en caracteres). Para conocer la semántica de longitud de las columnas existentes, consulte la columna CHAR_USED de la vista del diccionario de datos ALL_, USER_ o DBA_TAB_COLUMNS.

Hay información adicional y restricciones en la documentación anterior. Aquí hay una demostración de cómo intentar reducir la precisión de una columna de Número y reducir la longitud de un Varchar2. Puede probar otros cambios para saber qué sucederá.

--Setup.
DROP TABLE FOO;
CREATE TABLE FOO (BAR Number, BAR2 VARCHAR2(300));
INSERT INTO FOO (SELECT Level, RPAD(to_char(Level),10*Level,to_char(Level)) 
   FROM DUAL CONNECT BY Level <=20);
COMMIT;
SELECT * FROM FOO;

--Reduce Number to Number(10).
ALTER TABLE FOO MODIFY (BAR NUMBER (10));

--Reduce Varchar2(300) to Varchar2(100) (data would be truncated).
ALTER TABLE FOO MODIFY (BAR2 VARCHAR2(100));

--Reduce Varchar2(300) to Varchar2(200) (no data would be truncated).
ALTER TABLE FOO MODIFY (BAR2 VARCHAR2(200));

Las declaraciones alter tienen el siguiente resultado:

ALTER TABLE FOO MODIFY (BAR NUMBER (10))
Error report:
SQL Error: ORA-01440: column to be modified must be empty to decrease precision or scale
01440. 00000 -  "column to be modified must be empty to decrease precision or scale"

ALTER TABLE FOO MODIFY (BAR2 VARCHAR2(100))
Error report:
SQL Error: ORA-01441: cannot decrease column length because some value is too big
01441. 00000 -  "cannot decrease column length because some value is too big"

table FOO altered.

Reduzca la precisión creando una nueva columna.

ALTER TABLE FOO ADD (BAR3 NUMBER(10));
UPDATE FOO SET Bar3 = Bar;
ALTER TABLE FOO DROP COLUMN BAR;
ALTER TABLE FOO RENAME COLUMN BAR3 TO BAR;
Leigh Riffel
fuente
Entonces, la conclusión es: si desea disminuir la precisión o la escala de la columna y mantener elementos como índices, claves, etc., la única forma de hacerlo es copiar la tabla, truncarla, cambiar los tipos, copiar datos nuevamente y soltarla. La mesa temporal. ¿No hay una manera más rápida y elegante?
mnowotka
1
Bueno, podría crear una nueva columna, copiar los datos, volver a crear el índice, soltar la columna anterior y cambiar el nombre de la nueva. También puede usar DBMS_REDEFINITION, o puede crear una nueva tabla, copiar los datos, descartar la tabla anterior y cambiar el nombre de la nueva. O puede exportar la tabla, soltarla, volver a crearla con la nueva definición e importar los datos. Hay muchas maneras de hacer esto, pero más rápido / más elegante es algo que tendrá que decidir.
Leigh Riffel
Probablemente también pueda crear una nueva columna, copiar los datos en ella, establecer la columna anterior en nula, modificar su longitud, copiar los datos de la nueva columna a la columna anterior modificada y soltar la nueva columna. Y todo eso porque Oracle no permite reducir las columnas numéricas a pesar de que los datos encajarían. 8- {
Hans-Peter Störr