Was passiert, wenn Sie die Länge einer Spalte ändern (reduzieren)?

10

Nehmen wir an, ich habe zwei Spalten vom Typ NUMBER(ohne Genauigkeit und Skalierung) und VARCHAR(300). Ich habe festgestellt, dass diese Spalten für meine Daten viel zu groß sind, daher möchte ich sie in NUMBER(11)und ändern VARCHAR(10). Wenn ich diese SQL-Anweisung ausführe:

ALTER TABLE FOO
    MODIFY(BAR NUMBER(10));
  • Kann ich das in einer nicht leeren Spalte tun?
  • Wenn ja, was, wenn es einen Wert gibt, der größer ist als NUMBER(10), wird Orakel mir davon erzählen?
  • Bleiben die Spaltenstandardwerte unverändert, wenn sie zuvor definiert wurden?
  • Bleibt die Option "Spalte nullbar" unverändert?
  • Bleibt der primäre, fremde und eindeutige Schlüssel in dieser Spalte unverändert?
  • Bleiben die Einschränkungen für diese Spalten unverändert?
  • Bleiben die Indizes für diese Spalten unverändert?

Gibt es eine offizielle Dokumentation, die meine Fragen beantwortet?

mnowotka
quelle

Antworten:

12

Das Oracle Administrators Guide enthält Folgendes:

Verwenden Sie die Anweisung ALTER TABLE ... MODIFY, um eine vorhandene Spaltendefinition zu ändern. Sie können den Spaltendatentyp, den Standardwert, die Spaltenbeschränkung, den Spaltenausdruck (für virtuelle Spalten) und die Spaltenverschlüsselung ändern.

Sie können die Länge einer vorhandenen Spalte erhöhen oder verringern, wenn alle vorhandenen Daten der neuen Länge entsprechen. Sie können eine Spalte von Bytesemantik in CHAR-Semantik oder umgekehrt ändern. Sie müssen den Initialisierungsparameter BLANK_TRIMMING = TRUE setzen, um die Länge einer nicht leeren CHAR-Spalte zu verringern.

Wenn Sie eine Tabelle ändern, um die Länge einer Spalte vom Datentyp CHAR zu erhöhen, müssen Sie sich darüber im Klaren sein, dass dies eine zeitaufwändige Operation sein kann und erheblichen zusätzlichen Speicherplatz erfordern kann, insbesondere wenn die Tabelle viele Zeilen enthält. Dies liegt daran, dass der CHAR-Wert in jeder Zeile leer aufgefüllt werden muss, um die neue Spaltenlänge zu erfüllen.

Die Oracle SQL-Sprachreferenz enthält viel mehr Details, einschließlich der folgenden:

Sie können den Datentyp einer beliebigen Spalte ändern, wenn alle Zeilen der Spalte Nullen enthalten. Wenn Sie jedoch den Datentyp einer Spalte in einer Containertabelle für materialisierte Ansichten ändern, macht Oracle Database die entsprechende materialisierte Ansicht ungültig.

Sie können jederzeit die Größe eines Zeichens oder einer Rohspalte oder die Genauigkeit einer numerischen Spalte erhöhen, unabhängig davon, ob alle Zeilen Nullen enthalten oder nicht. Sie können die Größe eines Datentyps einer Spalte reduzieren, solange für die Änderung keine Daten geändert werden müssen. Die Datenbank durchsucht vorhandene Daten und gibt einen Fehler zurück, wenn Daten vorhanden sind, die die neue Längenbeschränkung überschreiten.

Sie können eine DATE-Spalte in TIMESTAMP oder TIMESTAMP WITH LOCAL TIME ZONE ändern. Sie können jeden TIMESTAMP WITH LOCAL TIME ZONE in eine DATE-Spalte ändern.

Wenn die Tabelle leer ist, können Sie das führende Feld oder den Sekundenbruchteil einer Datums- / Zeit- oder Intervallspalte erhöhen oder verringern. Wenn die Tabelle nicht leer ist, können Sie nur das führende Feld oder den Bruchteil einer Sekunde einer Datums- oder Intervallspalte erhöhen.

Für CHAR- und VARCHAR2-Spalten können Sie die Längensemantik ändern, indem Sie CHAR (um die Zeichensemantik für eine Spalte anzugeben, die ursprünglich in Bytes angegeben wurde) oder BYTE (um die Bytesemantik für eine Spalte anzugeben, die ursprünglich in Zeichen angegeben wurde) angeben. Um die Längensemantik vorhandener Spalten zu lernen, fragen Sie die Spalte CHAR_USED der Datenwörterbuchansicht ALL_, USER_ oder DBA_TAB_COLUMNS ab.

Die obige Dokumentation enthält zusätzliche Informationen und Einschränkungen. Hier ist eine Demonstration des Versuchs, die Genauigkeit einer Zahlenspalte und die Länge eines Varchar2 zu verringern. Sie können andere Änderungen ausprobieren, damit Sie wissen, was passieren wird.

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

Die alter-Anweisungen haben die folgende Ausgabe:

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.

Reduzieren Sie die Genauigkeit, indem Sie eine neue Spalte erstellen.

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
quelle
Die Schlussfolgerung lautet also: Wenn Sie die Genauigkeit oder Skalierung der Spalte verringern und beispielsweise Indizes, Schlüssel usw. beibehalten möchten, besteht die einzige Möglichkeit darin, die Tabelle zu kopieren, abzuschneiden, Typen zu ändern, Daten zurück in sie zu kopieren und zu löschen die temporäre Tabelle. Es gibt keinen schnelleren und eleganteren Weg?
Mnowotka
1
Nun, Sie könnten eine neue Spalte erstellen, die Daten kopieren, den Index neu erstellen, die alte Spalte löschen und die neue umbenennen. Sie können auch DBMS_REDEFINITION verwenden oder eine neue Tabelle erstellen, die Daten kopieren, die alte Tabelle löschen und die neue umbenennen. Oder Sie können die Tabelle exportieren, löschen, mit der neuen Definition neu erstellen und die Daten importieren. Es gibt viele Möglichkeiten, dies zu tun, aber schneller / eleganter müssen Sie sich entscheiden.
Leigh Riffel
Wahrscheinlich können Sie auch eine neue Spalte erstellen, die Daten in diese Spalte kopieren, die alte Spalte auf null setzen, ihre Länge ändern, die Daten aus der neuen Spalte zurück in die geänderte alte Spalte kopieren und die neue Spalte löschen. Und das alles, weil Oracle es nicht erlaubt, numerische Spalten zu reduzieren, obwohl die Daten passen würden. 8- {
Hans-Peter Störr