2012-03-26 3 views
5

テーブルに列を追加しようとしましたが、DEFAULT句で驚くべき効果がありました。既存の行を持つ表では、私はそうのような新しい列を追加しました:私は、その後、テーブルにチェック制約を追加するとOracleでは、charセマンティクスを持つ列に対してデフォルト値がサポートされていますか?

alter table t add c char(1 char) default 'N' not null; 

は、それが失敗しました:

alter table t add constraint chk check(c in ('N', 'Y')); 

ERROR at line 1: 
ORA-02293: cannot validate (T.CHK) - check constraint violated. 
をもたらしました

その他の情報:

  1. ので、私は単位を明示的に設定しています(つまり、char(1)とは対照的にchar(1 char)).nls_length_semanaticsの値が適切であるとは思いません。
  2. 列をchar(1 char)として追加した後、新しく追加された "N"は実際には "N"で、余分な空白が何であるか分かりません。
  3. 列をchar(1バイト)として追加すると、期待どおりに動作します。
  4. "default 'N' not null"を指定せずに既存のすべての行を 'N'に更新した後、列を 'not null'に変更すると、期待どおりに動作します。
  5. NLS_CHARACTERSETはAL32UTF8ですが、関連性があるとは思われません。
  6. データベースはOracle 11gです。 11.2.0.1.0。

ありがとうございます。

+0

の行に値を格納していない行を更新するUPDATEを発行することができ、なぜそれを作る(1バイト)? – tbone

+2

CHECK制約を 'CHECK(C IN(TO_NCHAR( 'N')、TO_NCHAR( 'Y')))'として書き直してください。関数の呼び出しがチェック制約で許可されているかどうかはわかりませんが、少なくともショットに値する可能性があります。興味深い。 –

答えて

2

oracle11gというタグを付けましたが、バージョンを指定していません。

これはLinux x86-64の11.2.0.2で動作します。

SQL*Plus: Release 11.2.0.2.0 Production on Mon Mar 26 13:13:52 2012 

Copyright (c) 1982, 2010, Oracle. All rights reserved. 

Connected to: 
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - 64bit Production 
With the Partitioning, Real Application Clusters, Automatic Storage Management and OLAP options 

SQL> create table tt(a number); 

Table created. 

SQL> insert into tt values (1); 

1 row created. 

SQL> commit; 

Commit complete. 

SQL> alter table tt add c char(1 char) default 'N' not null; 

Table altered. 

SQL> alter table tt add constraint chk check(c in('N','Y')); 

Table altered. 

SQL> select * from tt; 

    A C 
---------- - 
    1 N 

SQL> column dump(c) format a30 
SQL> select c, length(c),dump(c) from tt; 

C LENGTH(C) DUMP(C) 
- ---------- ------------------------------ 
N  1 Typ=96 Len=1: 78 

だから、おそらくあなたのバージョンにバグがありますか?

希望に役立ちます。

+0

私はWindowsとLinuxの両方、Oracle 11.2.0.1.0で試しました。それはおそらくマイナーバージョンのバグです。私は更新で試してみる。ありがとう。 –

+3

@ Mark J. Bobak - データベースの文字セットは何ですか?私の賭けは、可変幅文字セット(すなわち、 'AL32UTF8')を持つデータベースでのみ発生するということです。 –

+0

@JustinCave FTW!私はそれが可変幅文字セットだと思います。 Oracleは、可変幅キャラクタ・セットによって許容される最大幅を割り当て、最大バイトを使用しない文字については残りを埋めなければなりません。 –

2

前述のように、ORA-02293エラーの原因は、「N」ではなく「N」(埋め込み空白を含む)を挿入しているためです。あなたの制約に違反しています。

もっと興味深い質問は、なぜそのスペースを追加するのでしょうか?まあ、定義上、CHARは固定幅で、VARCHARは固定幅ではありません。 CHARは常に、その列に割り当てられたメモリ空間全体を満たすために空白を埋め込みます。 1 CHARの幅を選択し、AL32UTF8が可変幅文字セットであるため、CHARの固定幅の性質と矛盾するように見えます。 'N'で使用されていない余分なバイトを埋めるようにパディングされているようです。または、少なくとも、私はそれが起こっていると仮定します。

5

私は何を見ていることは

  • は、まず対話するカップルの異なるものに依存しているバグであると信じているが、データベース・キャラクタ・セットは、そのように(すなわちAL32UTF8)可変幅のキャラクタ・セットでなければなりません1文字の場合、最大4バイトのストレージが必要になることがあります。
  • 第2に、列は文字長セマンティクスで宣言する必要があります
  • 第11回から開始します。1では、テーブルのすべての行にデフォルト値を実際に格納するのではなく、データ・ディクショナリを更新するだけで、NOT NULLと宣言された列をテーブルに追加してDEFAULTを追加すると最適化されました。

これらの両方が真の場合、返される値の長さは4で、CHR(0)文字で埋められているようです。あなたが実際にテーブルに格納する値を強制する場合

SQL> select * from v$version; 

BANNER 
-------------------------------------------------------------------------------- 
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production 
PL/SQL Release 11.2.0.1.0 - Production 
CORE 11.2.0.1.0  Production 
TNS for 64-bit Windows: Version 11.2.0.1.0 - Production 
NLSRTL Version 11.2.0.1.0 - Production 

SQL> create table foo(col1 number); 

Table created. 

SQL> insert into foo values(1); 

1 row created. 

SQL> commit; 

Commit complete. 

SQL> alter table foo add c char(1 char) default 'N' not null; 

Table altered. 

SQL> alter table foo add constraint chk_foo check(c in ('Y', 'N')); 
alter table foo add constraint chk_foo check(c in ('Y', 'N')) 
           * 
ERROR at line 1: 
ORA-02293: cannot validate (SCOTT.CHK_FOO) - check constraint violated 

SQL> select c, dump(c) from foo; 

C DUMP(C) 
---- ------------------------------ 
N Typ=1 Len=4: 78,0,0,0 

することは、あなたは何CHR(0)パディングがありません期待される動作を取得します。だから私はテーブルに新しい行を挿入すると、それはパスします。

SQL> insert into foo(col1) values (2); 

1 row created. 

SQL> select c, dump(c) from foo; 

C DUMP(C) 
---- ------------------------------ 
N Typ=1 Len=4: 78,0,0,0 
N Typ=1 Len=1: 78 

また、値のみが「N」または「Y」であることをしている場合、実際にテーブル

SQL> update foo 
    2  set c = 'N' 
    3 where c != 'N'; 

1 row updated. 

SQL> select c, dump(c) from foo; 

C DUMP(C) 
---- ------------------------------ 
N Typ=1 Len=1: 78 
N Typ=1 Len=1: 78 
+3

上記の私の例とコメントも見てください。これは明らかに11.2.0.1.0のバグであり、11.2.0.2.0で修正されています。 –

関連する問題