O que acontece quando você modifica (reduz) o comprimento de uma coluna?

10

Digamos que eu tenho duas colunas do tipo NUMBER(sem precisão e escala) e VARCHAR(300). Vi que essas colunas são muito grandes para meus dados, então quero modificá-las para NUMBER(11)e VARCHAR(10). Então, se eu executar esta instrução SQL:

ALTER TABLE FOO
    MODIFY(BAR NUMBER(10));
  • Serei capaz de fazer isso na coluna não vazia?
  • Se sim, o que se houver um valor maior que NUMBER(10), a Oracle me falará sobre isso?
  • Os valores padrão da coluna permanecerão inalterados se definidos anteriormente?
  • A opção anulável da coluna permanecerá inalterada?
  • A chave primária, estrangeira e exclusiva nessa coluna permanecerá inalterada?
  • As restrições envolvendo essas colunas permanecerão inalteradas?
  • Os índices nessas colunas permanecerão inalterados?

Existe alguma documentação oficial respondendo minhas perguntas?

mnowotka
fonte

Respostas:

12

O Oracle Administrators Guide diz o seguinte:

Use a instrução ALTER TABLE ... MODIFY para modificar uma definição de coluna existente. Você pode modificar o tipo de dados da coluna, valor padrão, restrição de coluna, expressão de coluna (para colunas virtuais) e criptografia de coluna.

Você pode aumentar o comprimento de uma coluna existente ou diminuí-lo, se todos os dados existentes satisfizerem o novo comprimento. Você pode alterar uma coluna da semântica de bytes para a semântica de CHAR ou vice-versa. Você deve definir o parâmetro de inicialização BLANK_TRIMMING = TRUE para diminuir o comprimento de uma coluna CHAR não vazia.

Se você estiver modificando uma tabela para aumentar o comprimento de uma coluna do tipo de dados CHAR, perceba que esta pode ser uma operação demorada e pode exigir armazenamento adicional substancial, especialmente se a tabela contiver muitas linhas. Isso ocorre porque o valor CHAR em cada linha deve ser preenchido em branco para satisfazer o novo comprimento da coluna.

O Oracle SQL Language Reference tem muito mais detalhes, incluindo o seguinte:

Você pode alterar o tipo de dados de qualquer coluna se todas as linhas da coluna contiverem nulos. No entanto, se você alterar o tipo de dados de uma coluna em uma tabela de contêiner de exibição materializada, o Oracle Database invalidará a exibição materializada correspondente.

Você sempre pode aumentar o tamanho de um caractere ou coluna bruta ou a precisão de uma coluna numérica, independentemente de todas as linhas conterem nulos. Você pode reduzir o tamanho de um tipo de dados de uma coluna, desde que a alteração não exija que os dados sejam modificados.O banco de dados verifica os dados existentes e retorna um erro se existirem dados que excedam o novo limite de comprimento.

Você pode modificar uma coluna DATE para TIMESTAMP ou TIMESTAMP COM Fuso Horário Local. Você pode modificar qualquer TIMESTAMP WITH LOCAL TIME ZONE para uma coluna DATE.

Se a tabela estiver vazia, você poderá aumentar ou diminuir o campo inicial ou o segundo valor fracionário de uma coluna datetime ou interval. Se a tabela não estiver vazia, você poderá aumentar apenas o campo inicial ou o segundo fracionário de uma coluna de data e hora ou intervalo.

Para colunas CHAR e VARCHAR2, é possível alterar a semântica de comprimento especificando CHAR (para indicar semântica de caracteres para uma coluna que foi originalmente especificada em bytes) ou BYTE (para indicar semântica de bytes para uma coluna que foi especificada originalmente em caracteres). Para aprender a semântica de comprimento das colunas existentes, consulte a coluna CHAR_USED da visualização do dicionário de dados ALL_, USER_ ou DBA_TAB_COLUMNS.

Há informações e restrições adicionais na documentação acima. Aqui está uma demonstração da tentativa de reduzir a precisão de uma coluna Número e reduzir o comprimento de um Varchar2. Você pode tentar outras alterações para saber o que acontecerá.

--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));

As instruções alter têm a seguinte saída:

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.

Reduza a precisão criando uma nova coluna.

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
fonte
Portanto, a conclusão é: se você deseja diminuir a precisão ou a escala da coluna e manter itens como índices, chaves etc., a única maneira de fazer isso é copiar a tabela, truncá-la, alterar tipos, copiar dados para ela e soltar a mesa temporária. Não há maneira mais rápida e elegante?
mnowotka
11
Bem, você pode criar uma nova coluna, copiar os dados, recriar o índice, soltar a coluna antiga e renomear a nova. Você também pode usar DBMS_REDEFINITION ou criar uma nova tabela, copiar os dados, soltar a tabela antiga e renomear a nova. Ou você pode exportar a tabela, descartá-la, recriá-la com a nova definição e importar os dados. Existem várias maneiras de fazer isso, mas mais rápido / elegante é algo que você terá que decidir.
Leigh Riffel
Provavelmente, você também pode criar uma nova coluna, copiar os dados para ela, definir a coluna antiga como nula, modificar seu comprimento, copiar os dados da nova coluna para a coluna antiga alterada e soltar a nova coluna. E tudo isso porque o oracle não permite reduzir colunas numéricas, mesmo que os dados se ajustem. 8- {
Hans-Peter Störr