web-dev-qa-db-ja.com

ORA-02270:この列リストには一致する一意キーまたは主キーがありません

次のエラーレポートが表示されます。

エラーレポート-
 SQLエラー:ORA-02270:この列リストに一致する一意キーまたは主キーがありません
 02270。 00000-"この列リストに一致する一意キーまたは主キーはありません" 
 *原因:CREATE/ALTER TABLEステートメントのREFERENCES句
は、一致する一意キーがない列リストを提供しますまたは参照されているテーブルの主
キー制約。
 *アクション:ALL_CONS_COLUMNS 
カタログビューを使用して正しい列名を見つけます

理由をお聞かせいただけますか?

親テーブル

    CREATE TABLE STUDENTINFO
    (
      Student_ID VARCHAR2 (10) PRIMARY KEY,
      Full_Name VARCHAR2 (50) NOT NULL,
      Contact_Number NUMBER (15)NOT NULL,
      Address VARCHAR2 (50) NOT NULL,
      Nationality VARCHAR2 (15) NOT NULL,
      IC_PassportNo VARCHAR2 (15) NOT NULL,
      Programme VARCHAR (75) NOT NULL,
      Email_Address VARCHAR2 (50) NOT NULL REFERENCES                    USERNAMEPASSWORD(Username),
      Parents_Number NUMBER (15)NOT NULL,
      Fingerprint_Template clob
    );

子テーブル

    create table bit_2015_sep_cit4114_fyp_G_
    ( 
      Student_ID VARCHAR2 (10) PRIMARY KEY REFERENCES STUDENTINFO(Student_ID),
      Full_Name VARCHAR2 (50) NOT NULL REFERENCES STUDENTINFO(Full_Name),
      Nationality VARCHAR2 (15) NOT NULL REFERENCES STUDENTINFO(Nationality),
      Fingerprint_Template CLOB NOT NULL REFERENCES        STUDENTINFO(Fingerprint_Template),
     "23/10/2015" VARCHAR2 (15) not null, 
   );

国籍と指紋は重複しないようにしています。これは、studentinfoに保存されているすべての情報に基づいて確認するのに時間がかかるため、個々のクラスに分類する方が簡単かつ高速になるためです。テーブルの場合と同様に、STUDENTINFOは100万レコードで構成され、テーブルではbit_2015_sep_cit4114_fyp_G_には40レコードのみが含まれます。テーブルの国籍の値に基づいて計算されたビザ更新であるテーブル構造にさらに1つの列があるため、国籍の列を保持します。

5

一意でない別のテーブルの列を参照しているため、エラーが発生しました。 LennartとBalazs Pappはすでに良い答えを出しています。

親テーブルに一意の列が必要な理由を説明したいと思います。あなたが言ったように、あなたはテーブルを作成している間不可能である外部キーのために使われるカラムで重複した値を保持したいです。ただし、重複する値を含む既存のテーブルへの参照を作成できます。

一意でないインデックスとNOVALIDATEオプションを使用して主キーを作成すると、それが可能になります。しかし、これは混乱を招く結果につながる可能性があります。

状況を説明させてください。

1つの列IDを持つテーブルを作成しました。これには、一意でないインデックスを持つ主キー制約があります。

SQL>CREATE TABLE t1(id NUMBER);
SQL>CREATE INDEX t1_index on t1(id);
SQL>INSERT INTO t1 VALUES(1);
SQL>INSERT INTO t1 VALUES(1);
SQL>COMMIT;
SQL>SELECT id FROM t1;

    ID
----------
     1
     1

SQL>ALTER TABLE t1 ADD CONSTRAINT t1_pk PRIMARY KEY (id) USING INDEX t1_index NOVALIDATE;

最初のテーブルを参照する別のテーブルを作成してみましょう。

SQL>CREATE TABLE t2(id NUMBER, CONSTRAINT t2_fk FOREIGN KEY(id) REFERENCES t1(id));

いくつかのレコードを生成します。

SQL>INSERT INTO t2 VALUES(1);
SQL>COMMIT;

テーブルt2の値は1で、これは親テーブルt1を参照していますが、これは1の値が重複しています。子テーブルのidはどれを参照しますか?

上記のシナリオでは、外部キーは正常に機能しますが、テーブルt1の主キーは新しい値に対してのみ機能します。

結論:外部キーは常に、OracleでPRIMARY KEYまたはUNIQUEとして宣言された1つまたは複数の列を参照する必要があります。

5
JSapkota

フルネームなどは親テーブルで一意として宣言されていないため、子テーブルから参照することはできません。

なぜ子テーブルでこれらの列を複製する必要があるのですか?

編集:

子テーブルをロックすると、次のようになります。

create table bit_2015_sep_cit4114_fyp_G_
( ...
, Full_Name VARCHAR2 (50) NOT NULL 
      REFERENCES STUDENTINFO(Full_Name)

つまり、STUDENTINFOにはこのフルネームを持つ一意の行が必要です。つまりそのテーブルを宣言する必要があります:

CREATE TABLE STUDENTINFO
( ...
, Full_Name VARCHAR2 (50) NOT NULL
     UNIQUE,

Full_nameは一意ではないので、この列に対して外部キーを宣言することはできません。

後でパフォーマンスの問題が発生すると想定しているため、データベースを非正規化します。 IMOこれは大きな間違いです。正規化されたデータベースから始めて、そうする理由がある場合にのみ非正規化してください。

非正規化を主張する場合は、次のようなトリックを使用できます。

CREATE TABLE STUDENTINFO
( Student_ID VARCHAR2 (10) PRIMARY KEY
, Full_Name VARCHAR2 (50) NOT NULL
, Contact_Number NUMBER (15)NOT NULL
, Address VARCHAR2 (50) NOT NULL
, Nationality VARCHAR2 (15) NOT NULL
...
,    constraint AK1_STUDENTINFO unique (Student_ID, Full_Name, Nationality)

Student_IDは一意であるため、Student_ID、Full_Name、Nationalityも一意である必要があります。これが外部キーで使用できるかどうか疑問なので、Fingerprint_Templateを除外しました(ただし、追加できるかどうかはわかりません)。

create table bit_2015_sep_cit4114_fyp_G_
( Student_ID VARCHAR2 (10) PRIMARY KEY
, Full_Name VARCHAR2 (50) NOT NULL 
, Nationality VARCHAR2 (15) NOT NULL
...
,    constraint fk_studentinfo foreign key (Student_ID, Full_Name, Nationality)
                references studentinfo (Student_ID, Full_Name, Nationality)

);

しかし、前述のように、正規化された設計から始めて、それが機能するかどうかを確認します

6
Lennart

外部キー制約によって参照される列は、参照されるテーブルにPKまたは一意制約が必要です。これは、Full_NameNationalityFingerprint_Templateには当てはまりません。正直に言うと、これらのFK制約は不要であり、削除して、Student_IDでFK制約を維持します。また:

"23/10/2015" VARCHAR2 (15) not null, 

これは有効な列定義ではありません。これは:

column_name varchar2(15) default '23/10/2015' not null
3
Balazs Papp