Webアプリケーションで動作する既存のOracle 11gデータベーススキーマがあります。 Webサービスがデータベースでデータ操作を行えるように、アプリケーションの拡張を計画しています。計画の一部として、親/子関係のデータ整合性チェックがないため、他のアプリケーションでテーブルを操作することが問題になることがわかりました。 Webサービスで検証を行う予定ですが、データベースとWebサービスで検証を行うことをお勧めします。
--the base lookup table has a table with text values that is not shown.
--Example Red, Green,
CREATE TABLE PROPERTY
(
ID NUMBER(9) NOT NULL, --PRIMARY KEY
TENANT_ID NUMBER(9) NOT NULL
)
-- a property may or may not have a parent property.
--Example "Weight" of an item is a child of the "Shipping Weight"
CREATE TABLE PROPERTY_DEPENDENCY --PRIMARY KEY PROPERTY_ID,PROPERTY_TYPE_ID
(
PROPERTY_ID NUMBER(9) NOT NULL,
PARENT_PROPERTY_ID NUMBER(9),
PROPERTY_TYPE_ID NUMBER(9) NOT NULL,
ACTIVE NUMBER(1) NOT NULL
)
--examples "Item Colour", "Item Trim Colour","Shipping Weight", "Weight"
CREATE TABLE PROPERTY_TYPE
(
ID NUMBER(9) NOT NULL, --PRIMARY KEY
VALUE VARCHAR2(200 BYTE) NOT NULL,
PROPERTY_TYPE NUMBER(10) DEFAULT 1 NOT NULL
)
--and the table that you insert and update into
CREATE TABLE CASE_PROPERTY
(
ID NUMBER(9) NOT NULL, --PRIMARY KEY
PARENT_ID NUMBER(9), --constraint on PROPERTY
CASE_ID NUMBER(9) NOT NULL,--foreign key
PROPERTY_ID NUMBER(9), --constraint on PROPERTY
PROPERTY_TYPE_ID NUMBER(9) NOT NULL --constraint on PROPERTY_TYPE
)
これらは私が識別した問題です:
チェック制約を追加して、PARENT_ID <> PROPERTY_ID
が自分の親になれないようにすることができます。
編集3:実際の問題は、テーブルが適切に正規化されていないことです。これはレポートには適していますが、データの検証は困難です。 CASE_PROPERTY.PROPERTY_TYPE_ID
は常にPROPERTY_DEPENDENCY.PROPERTY_TYPE_ID
の値と同じである必要がありますが、これを検証する方法がわかりません。
CASE_PROPERTY
にデータの整合性を適用するトリガー以外の方法はありますか?
編集:完全な例をまとめます。 PROPERTY_DEPENDENCY
に外部キー制約を追加した場合、親を持つプロパティのみが挿入されたことを確認しますが、それらは正しい親ですか?
編集2:これは、許可される挿入の完全な例です。最後の2つの挿入は、許可されているが許可されていないデータの例です。
ALTER TABLE CASE_PROPERTY ADD CONSTRAINT CASE_PROPERTY_R01 FOREIGN
KEY (PARENT_ID) REFERENCES CASE_PROPERTY (ID) ENABLE VALIDATE
Insert into PROPERTY (ID, TENANT_ID) Values (2, 1);
Insert into PROPERTY (ID, TENANT_ID) Values (3, 1);
Insert into PROPERTY (ID, TENANT_ID) Values (4, 1);
Insert into PROPERTY_TYPE (ID,
VALUE, PROPERTY_TYPE) Values (10, 'Colour', 2);
Insert into PROPERTY_TYPE (ID,
VALUE, PROPERTY_TYPE) Values (11, 'Trim Colour', 1);
Insert into PROPERTY_TYPE (ID,
VALUE, PROPERTY_TYPE) Values (12, 'Shipping Weight', 1);
Insert into PROPERTY_TYPE (ID,
VALUE, PROPERTY_TYPE) Values (13, 'Weight', 3);
Insert into PROPERTY_DEPENDENCY (PROPERTY_ID,
PARENT_PROPERTY_ID, PROPERTY_TYPE_ID) Values (4, 3, 11);
Insert into PROPERTY_DEPENDENCY (PROPERTY_ID,
PARENT_PROPERTY_ID, PROPERTY_TYPE_ID) Values (3, NULL, 10);
Insert into PROPERTY_DEPENDENCY (PROPERTY_ID,
PARENT_PROPERTY_ID, PROPERTY_TYPE_ID) Values (1, NULL, 12);
Insert into PROPERTY_DEPENDENCY (PROPERTY_ID,
PARENT_PROPERTY_ID, PROPERTY_TYPE_ID) Values (2, 1, 13);
--example of a property validated data insert
--item 201 with type 13 is the child of item 200 of type 12
Insert into CASE_PROPERTY (ID,
PARENT_ID, CASE_ID, PROPERTY_ID, PROPERTY_TYPE_ID) Values (200, NULL, 3000, 1, 12);
Insert into CASE_PROPERTY (ID,
PARENT_ID, CASE_ID, PROPERTY_ID, PROPERTY_TYPE_ID) Values (201, 200, 3000, 2, 13);
--bad data inserts
-- a property is parent to itself with an incorrect property_type_id
Insert into CASE_PROPERTY (ID,
PARENT_ID, CASE_ID, PROPERTY_ID, PROPERTY_TYPE_ID) Values (202, 202, 4000, 3, 10);
--should be 202, null,4000,3,10
--a property is inserted with a parent that is not allowed
Insert into CASE_PROPERTY (ID,
PARENT_ID, CASE_ID, PROPERTY_ID, PROPERTY_TYPE_ID) Values (203, 200, 4000, 2, 13);
--parent property should be 1 not 2
かなりの数の変更が必要になるため、これが役立つかどうかはわかりませんが、問題は興味深いので、試してみます。
これらは主要な変更になります
ツリークロージャーでは、各祖先ノードがそれ自体を子孫としてポイントすることに注意してください。つまり、CaseProperty
では、再帰は_ID = ParentID
_ではなく_ParentID is NULL
_で停止します。
祖先になることを許可された親であるか、最初の1ステップだけであるかは、私には明らかではありません。クロージャーテーブルは祖先とすべての子孫を公開しているため、TreeClosure
には_Level Difference
_が追加され、AllowedCombos
はLevelDifference in (0,1)
のサブタイプになります。
単にPropertyID
ではなくAK _{PropertyID, PropertyTypeID}
_を伝播する
CaseProperty
での複合キーの使用
以下は、関係を明確にするためのモデルの主な制約です(構文の変更が必要になる場合があります)。
_ALTER TABLE Property ADD
CONSTRAINT PK_PR PRIMARY KEY (PropertyID)
, CONSTRAINT AK1_PR UNIQUE (PropertyID ,PropertyTypeID)
, CONSTRAINT FK1_PR FOREIGN KEY (PropertyTypeID)
REFERENCES PropertyType(PropertyTypeID)
;
ALTER TABLE TreeClosure ADD
CONSTRAINT PK_TC PRIMARY KEY (AncestorID ,DescendantID ,AncestorTypeID ,DescendantTypeID)
, CONSTRAINT FK1_TC FOREIGN KEY (AncestorID ,AncestorTypeID)
REFERENCES Property(PropertyID ,PropertyTypeID)
, CONSTRAINT FK2_TC FOREIGN KEY (DescendantID ,DescendantTypeID)
REFERENCES Property(PropertyID ,PropertyTypeID)
;
ALTER TABLE CaseProperty ADD
CONSTRAINT PK_CP PRIMARY KEY (CaseID, PropertyID, PropertyTypeID)
, CONSTRAINT FK1_CP FOREIGN KEY (CaseID)
REFERENCES Case(CaseID)
, CONSTRAINT FK2_CP FOREIGN KEY (PropertyID ,PropertyTypeID)
REFERENCES Property(PropertyID ,PropertyTypeID)
, CONSTRAINT FK4_CP FOREIGN KEY (ParentCaseID ,ParentPropertyID ,ParentPropertyTypeID)
REFERENCES CaseProperty(CaseID ,PropertyID ,PropertyTypeID)
, CONSTRAINT FK5_CP FOREIGN KEY (ParentPropertyID ,PropertyID , ParentPropertyTypeID ,PropertyTypeID)
REFERENCES AllowedCombos(AncestorID ,DescendantID , AncestorTypeID ,DescendantTypeID)
;
_