web-dev-qa-db-ja.com

再帰的なテーブルでデータの整合性を強化する

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
)

これらは私が識別した問題です:

  • cASE_PROPERTYに挿入して、プロパティを自分の親または祖父母にすることができます
  • pROPERTY_IDの間違ったPROPERTY_TYPE_IDをCASE_PROPERTYに挿入できます
  • cASE_PROPERTYに、PROPERTY_TYPE_IDには意味のないPARENT_IDを挿入できます

チェック制約を追加して、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
6
kevinsky

かなりの数の変更が必要になるため、これが役立つかどうかはわかりませんが、問題は興味深いので、試してみます。

これらは主要な変更になります

  • 参照階層の隣接リストの代わりにツリークロージャを使用する。クロージャテーブルには、すべての親からその子孫へのパスが含まれるため、考えられるすべての親子の組み合わせが公開されます。

ツリークロージャーでは、各祖先ノードがそれ自体を子孫としてポイントすることに注意してください。つまり、CasePropertyでは、再帰は_ID = ParentID_ではなく_ParentID is NULL_で停止します。

祖先になることを許可された親であるか、最初の1ステップだけであるかは、私には明らかではありません。クロージャーテーブルは祖先とすべての子孫を公開しているため、TreeClosureには_Level Difference_が追加され、AllowedCombosLevelDifference in (0,1)のサブタイプになります。

  • 単にPropertyIDではなくAK _{PropertyID, PropertyTypeID}_を伝播する

  • CasePropertyでの複合キーの使用


enter image description here


以下は、関係を明確にするためのモデルの主な制約です(構文の変更が必要になる場合があります)。

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

;
_
3
Damir Sudarevic