列の長さを変更(縮小)するとどうなりますか?


10

タイプNUMBER(精度とスケールなし)との2つの列があるとしVARCHAR(300)ます。私はそれらを変更したいので、これらの列は私のデータに対して大きすぎる方法であることを見たNUMBER(11)VARCHAR(10)。したがって、次のSQLステートメントを実行すると、

ALTER TABLE FOO
    MODIFY(BAR NUMBER(10));
  • 空でない列でそれを行うことはできますか?
  • もしそうなら、何よりも1つの値がある場合NUMBER(10)、オラクルはそれについて教えてくれますか?
  • 以前に定義されている場合、列のデフォルト値は変更されないままですか?
  • 列のNULL可能オプションは変更されませんか?
  • その列の主キー、外部キー、一意キーは変更されませんか?
  • その列を含む制約は変更されませんか?
  • その列のインデックスは変更されませんか?

私の質問に答える公式文書はありますか?

回答:


12

Oracle管理者ガイド』では、次のように述べられています。

ALTER TABLE ... MODIFYステートメントを使用して、既存の列定義を変更します。列のデータ型、デフォルト値、列の制約、列式(仮想列の場合)、および列の暗号化を変更できます。

既存のすべてのデータが新しい長さを満たす場合は、既存の列の長さを増やしたり、減らしたりできます。列をバイトセマンティクスからCHARセマンティクスに、またはその逆に変更できます。空でないCHAR列の長さを短くするには、初期化パラメータBLANK_TRIMMING = TRUEを設定する必要があります。

データ型CHARの列の長さを増やすためにテーブルを変更する場合、これは時間がかかる操作であり、特にテーブルに多くの行が含まれている場合は、かなりの追加ストレージが必要になる可能性があることに注意してください。これは、新しい列の長さを満たすために、各行のCHAR値に空白を埋め込む必要があるためです。

Oracle SQL言語リファレンス』には、次のような詳細が含まれています。

列のすべての行にnullが含まれている場合は、列のデータ型を変更できます。ただし、マテリアライズド・ビューのコンテナ表の列のデータ型を変更すると、対応するマテリアライズド・ビューが無効になります。

すべての行にnullが含まれているかどうかに関係なく、文字列またはraw列のサイズまたは数値列の精度をいつでも増やすことができます。データを変更する必要がない限り、列のデータ型のサイズを小さくできます。データベースは既存のデータをスキャンし、新しい長さ制限を超えるデータが存在する場合はエラーを返します。

DATE列をTIMESTAMPまたはTIMESTAMP WITH LOCAL TIME ZONEに変更できます。TIMESTAMP WITH LOCAL TIME ZONEをDATE列に変更できます。

テーブルが空の場合、日時列または時間隔列の先行フィールドまたは小数秒の値を増減できます。テーブルが空でない場合は、日時列または間隔列の先行フィールドまたは小数秒のみを増やすことができます。

CHARおよびVARCHAR2列の場合、長さセマンティクスを変更するには、CHAR(最初はバイトで指定された列の文字セマンティクスを示す)またはBYTE(最初は文字で指定された列のバイトセマンティクスを示す)を指定します。既存の列の長さセマンティクスを確認するには、ALL_、USER_、またはDBA_TAB_COLUMNSデータディクショナリビューのCHAR_USED列をクエリします。

上記のドキュメントには追加情報と制限があります。以下は、Number列の精度を下げ、Varchar2の長さを短くしようとする試みのデモです。他の変更を試して、何が起こるかを知ることができます。

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

alterステートメントの出力は次のとおりです。

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.

新しい列を作成して精度を下げます。

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;

したがって、結論は-列の精度またはスケールを減らし、インデックス、キーなどを保持したい場合、それを行う唯一の方法は、テーブルをコピーし、切り捨て、型を変更し、データをコピーしてドロップすることです一時テーブル。より速く、よりエレガントな方法はありませんか?
mnowotka 2012年

1
さて、新しい列を作成し、データをコピーし、インデックスを再作成し、古い列を削除して、新しい列の名前を変更できます。DBMS_REDEFINITIONを使用することも、新しいテーブルを作成してデータをコピーし、古いテーブルを削除して新しいテーブルの名前を変更することもできます。または、テーブルをエクスポートしてドロップし、新しい定義でテーブルを再作成して、データをインポートすることもできます。これを行う方法はたくさんありますが、より速く/よりエレガントにすることはあなたが決めなければならないことです。
リーリフェル

おそらく、新しい列を作成し、そこにデータをコピーし、古い列をnullに設定し、その長さを変更し、新しい列から変更された古い列にデータをコピーして戻し、新しい列をドロップすることもできます。そして、オラクルはデータが収まるとしても数値列を減らすことを許可しないためです。8- {
Hans-PeterStörr2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.