データベース設計 制約とトリガ 講師: 福田 剛志 fukudat@fukudat.com http://www.fukudat.com/ データベース設計 1 制約とトリガ (constraints and triggers) • 制約 (constraint) とは,DBMSが強制するデー タ項目間の関係 – 例) キー制約 • トリガ (trigger) とは,ある条件が成立したとき (に限って)実行されるアクション – 条件の例) タプルが挿入されたとき – 制約よりも簡単に実装できる データベース設計 2 制約の種類 • キー (key) – 外部キー (foreign-key) または 参照整合性 (referential-integrity) • 値に基づく制約 (value-based constraints) – 属性の値に対する制約 • タプルに基づく制約 (tuple-based constraints) – タプル内の要素間の制約 • 表明 (assertion) – 任意の SQL boolean expression データベース設計 3 外部キー (foreign key) • リレーション 販売(飲み屋, 酒, 値段) について考 える • 属性「酒」の値は実際に存在することが求められ る. – すなわち,酒(名前,製造元) リレーションの(名前属 性)に値として現れている. • 「販売」リレーションの「酒」が「酒」リレーションの 「名前」でなければならないと言うような制約を 「外部キー制約」と言う データベース設計 4 SQLでの外部キーの表現方法 • キーワード REFERENCES を用いて, – 属性宣言の後に REFERENCES <relation>(<attributes>) をつけるか, – テーブル要素として FOREIGN KEY ( <list of attributes> ) REFERENCES <relation>( <attributes> ) • 参照される属性は,PRIMARY KEY か UNIQUE と宣言されていなければならない. データベース設計 5 例えば+: 属性宣言で • CREATE TABLE 酒 ( 名前 CHAR(20) PRIMARY KEY, 製造元 CHAR(20) ); • CREATE TABLE 販売 ( 飲み屋 CHAR(20), 酒 CHAR(20) REFERENCES 酒(名前), 値段 REAL ); データベース設計 6 例えば...: テーブル要素として • CREATE TABLE 酒 ( 名前 CHAR(20) PRIMARY KEY, 製造元 CHAR(20) ); • CREATE TABLE 販売 ( 飲み屋 CHAR(20), 酒 CHAR(20) 値段 REAL, FOREGN KEY 酒 REFERENCES 酒(名前) ); データベース設計 7 外部キー制約の強制 • リレーション R の属性からリレーション S の主 キー (primary key) に対する外部キー制約 (foreign-key constraint) があるとき,次の2種類 の制約違反(violation)が発生する可能性があ る: – R に対する挿入または更新によって,S にない値が 入力される. – S に対する削除または更新によって,R が参照して いた値がなくなる. データベース設計 8 制約違反の対処法 (1) • R = 販売, S = 酒 とする. • 販売に対する挿入や更新で,酒に存在しない値 が入力された場合は,拒否する. • 酒に対する削除や更新で,販売に存在する酒が なくなった場合は,3通りの対処法がある. – デフォルト (default): 変更を拒否する – 連鎖 (cascade): 販売に対しても同じ変更を施す • 酒の削除: 販売も削除する • 酒の更新: 販売もその値に更新する – 無効化 (set null): 販売の属性「酒」の値を NULL に データベース設計 9 例えば+: 連鎖 • 酒リレーションから 名前 = ‘久保田千寿’ のタプ ルを削除したなら – 販売リレーションから,酒 = ‘久保田千寿’ を満たす 全てのタプルを削除する • 酒リレーションの「久保田千寿」を「千寿」に変更 したなら – 販売リレーションの 酒 = ‘久保田千寿’ を満たす全 てのタプルを 酒 = ‘千寿’ と変更する. データベース設計 10 例えば+: 無効化 • 酒リレーションから 名前 = ‘久保田千寿’ のタプ ルを削除したなら – 販売リレーションから,酒 = ‘久保田千寿’ を満たす 全てのタプルを 酒 = NULL と変更する • 酒リレーションの「久保田千寿」を「千寿」に変更 したなら – 販売リレーションから,酒 = ‘久保田千寿’ を満たす 全てのタプルを 酒 = NULL と変更する データベース設計 11 対処法の選択 • 外部キー制約を宣言するとき,対処法のポリ シーを指定する. ON [UPDATE | DELETE] [SET NULL | CASCADE] • どちらも指定しなかった場合は,デフォルト(拒否 する) データベース設計 12 例えば+ • CREATE TABLE 販売 ( 飲み屋 CHAR(20), 酒 CHAR(20), 値段 REAL, FOREIGN KEY(酒) REFERENCES 酒(名前) ON DELETE SET NULL ON UPDATE CASCADE ); データベース設計 13 属性に基づく検査 (attribute-based check) • 特定の属性の値に対して制約条件を付与する. • 属性宣言の後に CHECK( <condition> ) を記 述する. • この条件には,制約が付与される属性の名前を 用いることができるが,その他のリレーションや 属性名は副問合せの中でのみ使用できる. データベース設計 14 例えば+ • CREATE TABLE 販売 ( 飲み屋 CHAR(20), 酒 CHAR(20) CHECK ( 酒 IN (SELECT 名前 FROM 酒)), 値段 REAL CHECK ( 値段 < 1000 ) ); データベース設計 15 検査のタイミング • 属性に基づく検査は,その属性の値が挿入また は更新されたときにだけ検査される. – 例えば: CHECK (値段 < 1000) は値段に新しい値 が入力されるたびに検査され,1000円以上のとき拒 否する. – 例えば: CHECK (酒 IN (SELECT 名前 FROM 酒)) は酒リレーションに対する削除では検査されない. データベース設計 16 タプルに基づく検査 (tuple-based check) • CHECK ( <condition> ) は一つのテーブル要素 として宣言することもできる. • その場合,条件はそのリレーションの任意の属 性を参照することができる. • ほかのリレーションの属性は,副問合せないで のみ使用できる. • 挿入と更新でのみ検査される. データベース設計 17 例えば+ • 「高い店」だけが 1000円より高い酒を売ることが できる: • CREATE TABLE 販売 ( 飲み屋 CHAR(20), 酒 CHAR(20), 値段 REAL, CHECK (飲み屋 = ‘高い店’ OR 値段 <= 1000) ); データベース設計 18 表明 (assertion) • データベーススキーマの要素 • 定義方法: CREATE ASSERTION <名前> CHECK ( <条件> ); • 条件は任意のリレーションと属性を参照すること ができる データベース設計 19 例えば+ (1) • リレーション 販売(飲み屋,酒,値段) において,どの店 の平均価格は500円以下でなければならないとする. • CREATE ASSERTION ボッタクリ禁止 CHECK ( NOT EXISTS ( SELECT 飲み屋 FROM 販売 GROUP BY 飲み屋 HAVING 500 > AVG(値段) ) ); 平均価格が500円を超える飲み屋 データベース設計 20 例えば+ (2) • リレーション 酒飲み(名前,住所,電話番号) と 飲み屋(名前,住所) において,飲み屋の数は酒 飲みの人数より少なくなければならないとする • CREATE ASSERTION 数制限 CHECK ( (SELECT COUNT(*) FROM 飲み屋) < (SELECT COUNT(*) FROM 酒飲み) ); データベース設計 21 表明を検査するタイミング • 原則としては,リレーションに変更があった後に は,全ての表明を検査しなければならない. • しかし,賢いシステムはどの種類の変更の後に 表明を検査すべきか判断できる. – 例えば: 酒に対する変更は「数制限」に対する影響 はない.酒飲みに対する挿入も同じ データベース設計 22 問題点 • 属性に基づく検査,タプルに基づく検査には限 界がある • 表明はほとんどのアプリケーションに対して十分 な一般性があるが,効率的に実装することが難 しい – DBMS は,違反する可能性のない表明を検査しな いようにしなければならないが,簡単でない. データベース設計 23 解決策: トリガ (trigger) • トリガはユーザにいつ検査すべきか指定させる • 表明のように,トリガには一般の条件を記述する ことができ,任意の SQL による更新を実行する ことができる. データベース設計 24 イベント・条件・アクションルール (event-condition-action rule) • トリガはECAルール(event-condition-action rule) とも言う • イベント: データベースに対する変更の種類 – 例: 販売に対する挿入 • 条件: 任意の SQL条件式 • アクション: 任意の SQL文 データベース設計 25 例えば+ • 販売(飲み屋,酒,値段)に対して未知の酒が挿 入されたとき • 外部キー制約を使って拒否するのではなく • 酒(名前,製造元)リレーションにその酒を追加し たい – 製造元 = NULL にする データベース設計 26 例えば+: 定義方法 イベント • CREATE TRIGGER 酒トリガ AFTER INSERT ON 販売 REFERENCING NEW ROW AS NewTuple FOR EACH ROW WHEN (NewTuple.酒 NOT IN (SELECT 名前 FROM 酒)) INSERT INTO 酒(名前) 条件 VALUES(NewTuple.酒); アクション データベース設計 27 バリエーション (1) • AFTER BEFORE. – またリレーションがビューのときは INSTEAD OF が 使える • ビューに対する変更をベーステーブルの変更に変換する方 法として使える • INSERT DELETE または UPDATE. – UPDATE はさらに UPDATE B ON <属性> でも良い データベース設計 28 バリエーション (2) • トリガは行レベルか文レベルの2種類 • FOR EACH ROW をつけると,行レベルのトリ ガとなる.つけなければ文レベル • 行レベルのトリガは,タプルが変更されるたびに 1回実行される • 文レベルのトリガは,一つのSQL文が(何行変 更するかにかかわらず)1回実行される データベース設計 29 バリエーション (3) • REFERENCING は – INSERT 文の場合,新しいタプル (行レベルの場合 は 1つ; 文レベルの場合は タプルの集合) を表す. – DELETE 文の場合は,削除されるタプルの集合 – UPDATE 文の場合は,変更前と変更後の両方 を [NEW OLD][TUPLE TABLE] AS <名前> として参照するときに用いる データベース設計 30 バリエーション (4) • 条件には任意の条件式が書ける. • 条件式はトリガのイベントが発生する前 (BEFORE) か後 (AFTER) に評価される • REFERENCING 節で宣言された名前で,変更 によって影響されるタプルを参照することができ る. データベース設計 31 バリエーション (5) • アクションには一つ以上の SQL文が書ける – 複数文の場合はBEGIN と END で囲う • アクションに問合せ文は意味がないので,更新 文に限られる. データベース設計 32 別の例+ • 販売(飲み屋,酒,値段) に対して 100円以上の 値上げを行った飲み屋を ボッタクリ(飲み屋) と して保持することを考える. データベース設計 33 トリガの宣言 イベント 値段に対する変更があったとき • CREATE TRIGGER 値段トリガ AFTER UPDATE OF 値段 ON 販売 REFERENCING 変更前・後のタプルを参照 できるようにする OLD ROW as old NEW ROW as new 各行の変更を考慮する必要が あるので,行レベル FOR EACH ROW WHEN(new.値段 >= old.値段 + 100) INSERT INTO ボッタクリ 値段が100円以上, 値上がったか VALUES(new.飲み屋); アクション: ボッタクリに 値上げをした飲み屋を追加 データベース設計 34 ビューに対するトリガ • 一般には,ビューは変更することができない. • しかし INSTEAD OF トリガを使うと,ビューに対 する変更を意味のあるような変更に変換できる • 例えば+: ビュー つながり(酒飲み,酒,飲み 屋) を,酒飲みが好きな酒を売っている,その酒 飲みの行きつけの飲み屋の関係を表すように定 義する. データベース設計 35 ビューの定義 • CREATE VIEW つながり AS SELECT 好き.酒飲み, 好き.酒, 販売.飲み屋 FROM 好き, 販売, 行きつけ WHERE 好き.酒飲み = 行きつけ.酒飲み AND 好き.酒 = 販売.酒 AND 販売.飲み屋 = 行きつけ.飲み屋 好き,販売,行きつけリレーションを自然結合 データベース設計 36 ビューの更新の解釈方法 • つながりリレーションに挿入することはできない • しかし,INSTEAD OF トリガを用いて, (酒飲み,酒,飲み屋) タプルを好き,販売,行き つけに対する3つの挿入に変換することができる – ただし,販売の値段はわからないのでデフォルト値 NULL とする データベース設計 37 トリガの定義 • CREATE TRIGGER つながりトリガ INSTEAD OF INSERT ON つながり REFERENCING NEW ROW AS n FOR EACH ROW BEGIN INSERT INTO 好き VALUES(n.酒飲み, n.酒); INSERT INTO 販売(飲み屋, 酒) VALUES(n.飲み屋, n.酒); INSERT INTO 行きつけ VALUES(n.酒飲み, n.飲み屋); END; データベース設計 38
© Copyright 2024 Paperzz