データ整合性

この章では、整合性制約によって、データベースに関連するビジネス・ルールがどのように規定され、表への無効なエントリがどのように防止されるかについて説明します。

データ整合性の概要

データにおいては、データベース管理者やアプリケーション開発者が決めたビジネス・ルールに準拠した、データ整合性が維持されていることが重要です。

ビジネス・ルールには、常にtrueまたは常にfalseになる必要がある条件および関係を指定します。たとえば、各企業では、給与、従業員番号、在庫追跡などに関して独自のポリシーを定義します。

データ整合性を保証する方法

データベース・アプリケーションを設計する場合、開発者は、データベースに格納するデータの整合性を保証するためのいくつかのオプションを使用できます。

オプションは次のとおりです。

関連情報:

整合性制約の利点

整合性制約は、SQLを使用して作成および削除されるスキーマ・オブジェクトです。データの整合性を維持するために、可能な場合は常に整合性制約またはアサーションを使用します。

データの整合性を維持する方法として、整合性制約とアサーションには、次のような利点があります。

関連情報:

整合性制約のタイプ

Oracle AI Databaseでは、表レベルと列レベル、および複数の表を含むアサーションの両方で制約を適用できます。

列または属性の一部として指定される制約が、表内指定です。表定義の一部として指定される制約が、表外指定です。

キーとは、特定タイプの整合性制約の定義に含まれる列または列の集合のことです。キーによって、リレーショナル・データベースの表と列の間の関連が示されます。キーの中にある個々の値を、キー値と呼びます、

次の表に、制約のタイプを示します。表内指定であることが必要なNOT NULLを除き、どの制約も表内と表外のいずれかで指定できます。

表1整合性制約のタイプ

制約タイプ 摘要 参照
NOT NULL 指定した列でのNULLを含む行の挿入または更新を許可または禁止します。 「NOT NULL整合性制約」
一意キー 同じ列または列の組合せで、複数の行が同じ値を持つことを禁止しますが、一部の値がNULLであることを許可します。 一意制約
主キー NOT NULL制約と一意制約を結合します。これにより、同じ列または列の組合せで、複数の行が同じ値を持つことを禁止し、値がNULLであることを禁止します。 「主キー制約」
外部鍵 列を外部キーとして指定し、外部キーと、参照キーと呼ばれる主キーまたは一意キーの間の関係を確立する。 外部キーの制約に関する項
小切手 指定した条件をデータベース値が満たしている必要があります。 「チェック制約」
REF REF列の値で許可されるデータ操作のタイプ、およびその操作の結果として依存データが受ける影響について指示します。オブジェクト・リレーショナル・データベースでは、REFと呼ばれる組込みデータ型によって、指定したオブジェクト型の行オブジェクトへの参照がカプセル化されます。REF列に対する参照整合性制約によって、REFの行オブジェクトがあることが保証されます。 REF制約について学習するには、『Oracle AI Databaseオブジェクト・リレーショナル開発者ガイド』を参照してください
Assertions アサーションは、アプリケーションのデータベース表に対する副問合せを含むブール式です。アサーションには制約のセマンティクスがあります。つまり、トランザクションがデータを変更し、これらの変更をコミットしている間に、これらのブール式の真相を確認するためにデータベースが割り当てられます。 アサーションについて学習するには、「SQLアサーション」を参照してください

関連情報:

NOT NULL整合性制約

NOT NULL制約がある場合、表の列値にNULLを使用できません。NULLは、値がないことを示します。デフォルトでは、表内のすべての列でNULLを使用できます。

NOT NULL制約は、値が必須である列のためのものです。たとえば、hr.employees表ではemail列に値が必要です。電子メール・アドレスなしで従業員の行を挿入しようとすると、次のエラーが発生します。

SQL> INSERT INTO hr.employees (employee_id, last_name) values (999, 'Smith');
.
.
.
ERROR at line 1:
ORA-01400: cannot insert NULL into ("HR"."EMPLOYEES"."EMAIL")

NOT NULL制約付きの列を追加できるのは、表に行が1つも含まれていない表またはデフォルト値が指定された場合のみです。

関連情報:

一意制約

一意キー制約では、列(または列の集合)のすべての値が一意である必要があります。 一意キーの制約を設定されていると、表の行では、列(一意キー)または列の集合(コンポジット一意キー)で重複した値を持つことはありません。

ノート: キーという用語は、整合性制約で定義されている列のみを指します。データベースではキー列に対して索引を暗黙的に作成または再利用することで一意制約を規定するため、一意キーという用語は一意キー制約または一意索引のシノニムとして誤用されることがあります。

一意キー制約は、値の重複が許されない列に適しています。一意制約は、(各表の行を一意に識別することが目的である)主キー制約とは異なり、通常は、一意であること以外の意味を持たない値が含まれています。一意キーの例には次のものがあります。

例4-1に示すように、hr.employees表のemail列には一意キー制約が存在します。文の関連する部分は、次のとおりです。

CREATE TABLE employees    ( ...
    , email          VARCHAR2(25)
        CONSTRAINT   emp_email_nn  NOT NULL ...
    , CONSTRAINT     emp_email_uk  UNIQUE (email) ... );

次の例に示すように、emp_email_uk制約により、2人の従業員が同じ電子メール・アドレスを持つことはありません。

SQL> SELECT employee_id, last_name, email FROM employees WHERE email = 'PFAY';

EMPLOYEE_ID LAST_NAME                 EMAIL
----------- ------------------------- -------------------------
        202 Fay                       PFAY

SQL> INSERT INTO employees (employee_id, last_name, email, hire_date, job_id)
  1  VALUES (999,'Fay','PFAY',SYSDATE,'ST_CLERK');
.
.
.
ERROR at line 1:
ORA-00001: unique constraint (HR.EMP_EMAIL_UK) violated

NOT NULL制約も定義されている場合を除き、一意キー制約では、NULLは常に許可されます。このため、一意キー制約とNOT NULL制約の両方を持つ列が一般的に使用されます。これらの組合せにより、ユーザーは一意キーに必ず値を入力することになり、さらに新しい行データが既存の行データと競合することがなくなります。

ノート:複数の列に対する一意キー制約の検索メカニズムにより、一部がnullのコンポジット一意キー制約の非NULL列で同一の値は許されない。

例7-1 一意制約

SQL> SELECT employee_id, last_name, email FROM employees WHERE email = 'PFAY';

EMPLOYEE_ID LAST_NAME                 EMAIL
----------- ------------------------- -------------------------
        202 Fay                       PFAY

SQL> INSERT INTO employees (employee_id, last_name, email, hire_date, job_id)
  1  VALUES (999,'Fay','PFAY',SYSDATE,'ST_CLERK');
.
.
.
ERROR at line 1:
ORA-00001: unique constraint (HR.EMP_EMAIL_UK) violated

関連情報:

主キー制約

主キー制約では、制約の対象となる1つ以上の列グループの値によって、行が一意に識別されます。各表には1つの主キーを設定でき、この主キーにより行が識別され、行が重複しないことが保証されます。

主キーには、自然キーまたはサロゲート・キーを使用できます。自然キーは、表内の既存の属性から作成された、意味のある識別子です。たとえば、参照表の郵便番号を自然キーとして使用できます。

これに対し、サロゲート・キーは、システムで生成され、データが増加する識別子であり、表内での一意性が保証されます。通常、sequenceまたは UUIDはサロゲートキーを生成します。

Oracle AI Databaseでは、主キー制約の実装により、次のことが保証されます。

主キーが必要となる典型的な状況は、従業員用の数値識別子です。各従業員は一意のIDを持つ必要があります。従業員は、employees表の1つの行によってのみ記述する必要があります。

「一意制約」の例では、既存の従業員が従業員IDとして202を持っており、従業員IDが主キーであることが示されています。次に示す例では、同じ従業員IDを持つ従業員、およびIDを持たない従業員を追加します。

SQL> INSERT INTO employees (employee_id, last_name, email, hire_date, job_id)
  1  VALUES (202,'Chan','JCHAN',SYSDATE,'ST_CLERK');
.
.
.
ERROR at line 1:
ORA-00001: unique constraint (HR.EMP_EMP_ID_PK) violated

SQL> INSERT INTO employees (last_name) VALUES ('Chan');
.
.
.
ERROR at line 1:
ORA-01400: cannot insert NULL into ("HR"."EMPLOYEES"."EMPLOYEE_ID")

データベースにより、索引を持つ主キー制約は規定されます。通常、列に対して作成された主キー制約によって、暗黙的に一意索引とNOT NULL制約が作成されます。この規則には、次の例外がある点に注意してください。

デフォルトでは、暗黙的に作成された索引の名前が、主キー制約の名前になります。索引にはユーザー定義名を指定することもできます。制約の作成に使用するCREATE TABLE文またはALTER TABLE文にENABLE句を組み込んで、索引の記憶域オプションを指定できます。

関連項目:表に主キー制約を追加する方法を学習するには、『Oracle AI Database Oracle AI Database開発スタート・ガイド』および『Oracle AI Database開発ガイド』を参照してください

外部キーの制約

2つの表に1つ以上の共通の列が含まれる場合、Oracle AI Databaseでは、参照整合性拘束とも呼ばれる外部キー制約を介して2つの表の間の関係を規定できます。

外部キー制約では、制約が定義される列の各値に対して、他の表と列を指定するもう一方の列の値が一致する必要があります。参照整合性規則の例としては、既存の部門にのみ従事できる従業員があります。

次の表に、参照整合性制約に関連する用語を示します。

表2参照整合性制約の用語

用語 定義
外部鍵

制約の定義に含まれている列または列の集合のうち、参照キーを参照します。たとえば、employeesのdepartment_id列は外部キーであり、departmentsのdepartment_id列を参照します。

外部キーは、複数列として定義できます。ただし、コンポジット外部キーの列数とデータ型は、参照先のコンポジット主キーまたは一意キーと同じであることが必要です。

外部キーの値は、参照先の主キーまたは一意キーの値と一致するか、NULLであることが可能です。コンポジット外部キーのいずれかの列がNULLの場合、そのキーのNULL以外の部分は、親キーの対応部分と一致している必要はありません。

参照されたキー 表の一意キーまたは主キーで、外部キーによって参照されるキー。たとえば、departmentsのdepartment_id列は、employeesのdepartment_id列の参照キーです。
依存表または子表 外部キーを含む表。この表は、参照される一意キーまたは主キーにある値に依存しています。たとえば、employees表はdepartmentsの子です。
参照表または親表 子表の外部キーが参照する表。この表の参照キーにより、子表に対する特定の挿入または更新が許可されるかどうかが決まります。たとえば、departments表はemployeesの親です。

図7-1に、employees.department_id列の外部キーを示します。この列のすべての値が、departments.department_id列の値と一致することが保証されます。このため、employees.department_id列に間違った部門番号が存在することはありません。

図1: 参照整合性制約

画像cncpt056.gifの説明

自己参照型整合性制約

自己参照型整合性制約とは、同じ表の親キーを参照する外部キーのことです。

次の図では、自己参照型制約によって、employees.manager_id列のすべての値が、employees.employee_id列の既存の値に対応するようになります。たとえば、従業員102の管理職がemployees表に存在する必要があります。この制約によって、間違った従業員番号がmanager_id列に存在する可能性がなくなります。

図2: 単一表の参照制約

画像cncpt057.gifの説明

NULLと外部キー

リレーショナル・モデルでは、外部キーの値は、参照先の主キーまたは一意キーの値と一致するか、NULLであることが可能です。たとえば、hr.employeesの行で部門IDが指定されないことがあります。

コンポジット外部キーのいずれかの列がNULLの場合、そのキーのNULL以外の部分は、親キーの対応部分と一致している必要はありません。たとえば、reservations表のtable_id列およびdate列にはコンポジット外部キーが含まれるが、table_idはNULLであることがあります。

親キーの修正と外部キー

親キーを削除するとき、外部キーと親キーの間の関係が影響を及ぼします。たとえば、あるユーザーが部門のレコードの削除を試行すると、この部門の従業員のレコードに何が起こるかについて説明します。

親キーが変更された場合、参照整合性制約では、子表の依存行に対して実行される次のアクションを指定できます。

表7-3に、親表のキー値および子表の外部キー値に対する異なる参照アクションごとに可能なDML文の概要を示します。

表3更新NO ACTIONとDELETENO ACTIONで許可されるDML文

DML文 親表に対して発行 子表に対して発行
INSERT 親キー値が一意であれば常に発行できます。 外部キーの値が親キーに存在するか、外部キーの一部またはすべてがNULLの場合にのみ発行できます。
UPDATE NO ACTION 文の実行後に、参照される親キー値のない行が子表内に残らない場合は発行できます。 文の実行後も新しい外部キー値によって参照キー値が参照される場合は発行できます。
DELETE NO ACTION 子表のどの行も親キー値を参照していない場合は発行できます。 常に発行可能
DELETE CASCADE 常に発行可能 常に発行可能
DELETE SET NULL 常に発行可能 常に発行可能

ノート: Oracle DatabaseのFOREIGN KEY整合性制約でサポートされていないその他の参照アクションは、データベース・トリガーを使用して強制できます。「トリガーの概要」を参照してください。

ON DELETE句について学習するには、関連項目: 『Oracle AI Database SQL言語リファレンス』を参照してください。

索引と外部キー

通常、外部キーには索引付けが必要です。唯一の例外は、対応する一意キーまたは主キーの更新や削除が発生しないことが確実な場合です。

子表で外部キーの索引付けを行うと、次の利点があります。

関連情報:

制約のチェック

列または列の集合に対するチェック制約では、すべての行に対して、指定した条件がTRUEまたはUNKNOWSであることが必要です。

DMLの結果で制約の条件がFALSEに評価される場合、そのSQL文はロールバックされます。チェック制約の主な利点は、特殊な整合性規則を規定できることです。たとえば、チェック制約を使用すると、hr.employees表に次の規則を規定できます。

次の例では、employeesに最大給与制約を作成し、最大値を超える給与を含む行を文で挿入すると、どのようなことが起こるかを示します。

SQL> ALTER TABLE employees ADD CONSTRAINT max_emp_sal CHECK (salary < 10001);
SQL> INSERT INTO employees (employee_id,last_name,email,hire_date,job_id,salary)
  1  VALUES (999,'Green','BGREEN',SYSDATE,'ST_CLERK',20000);
.
.
.
ERROR at line 1:
ORA-02290: check constraint (HR.MAX_EMP_SAL) violated

1つの列に、定義された列を参照する複数のチェック制約を設定できます。たとえば、salary列には、10000より大きい値を禁止する1つの制約と、500未満の値を禁止する別の制約を設定できます。

単一の列に対して複数のチェック制約が存在する場合は、その目的が競合しないように設計する必要があります。また、条件は特定の順序では評価されません。データベースでは、チェック条件が矛盾しないかどうかは検証されません。

チェック制約の制限について学習するには、関連項目: 『Oracle AI Database SQL言語リファレンス』

事前チェック可能なCHECK制約

PRECHECKとマークされたチェック制約をデータベースの外部でチェックできます。

表の作成または変更中に、チェック制約をPRECHECK状態に設定します。PRECHECK状態は制約のENABLEおよびVALIDATE状態を補完するもので、3つすべての状態を同時にアクティブにできます。

JSONを使用してチェック制約を表す場合、Oracle AI Databaseでは、JSONスキーマのエクスポートおよびアプリケーション・クライアント内のJSONスキーマ・バリデータに対するJSONデータの検証ができます。制約がPRECHECK状態に設定されている場合、制約には、制約のセマンティクスを保持する同等のJSONスキーマが存在することを示します。クライアント・アプリケーション開発者は、クライアント・アプリケーション内で制約を事前検証できます。データベースにより制約がチェックされ、JSONスキーマで制約を表現できない場合はエラーが生成されます。

関連項目

アサーション

アサーションは、アプリケーションのデータベース表に対する副問合せを含むブール式です。

アサーションには制約のセマンティクスがあります。つまり、トランザクションがデータを変更し、これらの変更をコミットしている間に、これらのブール式の真相を確認するためにデータベースが割り当てられます。

次のSQL文は、NO_TRAINERS_IN_BOSTONというアサーションを作成し、ボストン・ベースの部門で採用されたトレーナがないことを要求します。最上位レベルのNOT EXISTSは、EMP表とDEPT表間の結合の結果セットを空のままにすることを要求するブール式を表します。

CREATE ASSERTION no_trainers_in_boston CHECK
(NOT EXISTS
   (SELECT 'trainer in Boston'
    FROM   emp e, dept d
    WHERE  e.deptno = d.deptno
      AND  e.job = 'TRAINER'
      AND  d.loc = 'BOSTON'));

アサーションはスキーマ・レベルのオブジェクトです。これは、他のスキーマの表がブール式によって参照される場合、それらの表にアクセスするためにASSERTION REFERENCESオブジェクト権限が必要であることを意味します。これは、2つのスキーマにまたがる外部キーとは異なります。つまり、異なるスキーマ内の表の主キーを指す外部キーを正常に作成するには、REFERENCESオブジェクト権限が必要です。

アサーションは、一般的なデータ整合性制約です。CHECK制約、PRIMARY KEY制約、UNIQUE制約およびFOREIGN KEY制約を置換するために使用できます。

たとえば、EMP表で次の制約があるとします。

これらの制約は、次のアサーションを使用して実装できます。

CREATE ASSERTION commission_not_greater_than_salary CHECK
(NOT EXISTS
  (SELECT ''
   FROM   emp e
   WHERE  e.comm > e.sal));
CREATE ASSERTION emp_empno_pk CHECK
(NOT EXISTS
  (SELECT ''
   FROM   emp e1, emp e2
   WHERE  e1.empno = e2.empno
     AND  e1.rowid != e2.rowid));
CREATE ASSERTION emp_ename_deptno_uk CHECK
(NOT EXISTS
  (SELECT ''
   FROM   emp e1, emp e2
   WHERE  e1.ename = e2.ename
     AND  e1.deptno = e2.deptno
     AND  e1.rowid != e2.rowid));
CREATE ASSERTION emp_fk_dept CHECK
(NOT EXISTS
  (SELECT ''
   FROM   emp e
   WHERE  NOT EXISTS
     (SELECT ''
      FROM   dept d
      WHERE  d.deptno = e.deptno)));

ただし、可能なかぎり常に制約を使用し、制約を使用できない場合にのみアサーションを使用することを強くお薦めします。

関連項目

整合性制約およびアサーションの状態

制約定義またはアサーション定義の一部として、Oracle AI Databaseがいつどのようにして制約またはアサーションを規定するかを指定できます。これにより、制約状態またはアサーション状態が決定されます。

変更されたデータおよび既存のデータのチェック

データベースでは、制約またはアサーションが既存のデータまたは将来のデータに適用されるかどうかを指定できます。制約またはアサーションが使用可能である場合、データベースでは、入力または更新された時点における新規データがチェックされます。制約またはアサーションに準拠しないデータをデータベースに入力することはできません。

たとえば、employees.department_idに対してNOT NULL制約を使用可能にすると、将来のすべての行が部門IDを持ちます。制約が使用禁止である場合、表には制約に違反する行を入力できます。

制約とアサーションは、次のいずれかの検証モードに設定できます。

VALIDATEおよびNOVALIDATEの動作は、常に、制約またはアサーションが使用可能であるか使用禁止であるかどうかによって異なります。次の表に関係をまとめます。

表4変更されたデータのチェックおよび既存のデータのチェック

変更済データ 既存のデータ 要約
ENABLE VALIDATE 既存のデータと将来のデータは制約またはアサーションに準拠する必要があります。データが入力されている表に新しい制約またはアサーションを適用しようとすると、既存の行がこの制約またはアサーションに違反する場合、エラーになります。
ENABLE NOVALIDATE データベースは制約またはアサーションをチェックしますが、制約はすべての行に関してTRUEである必要はありません。したがって、既存の行が制約またはアサーションに違反している可能性はありますが、新しい行または変更された行は規則に準拠する必要があります。このモードは、整合性がすでに検証されている既存のデータを含むデータ・ウェアハウスで使用されます。
DISABLE VALIDATE データベースでは制約が使用禁止になり、索引が削除されて、制約の対象となる列への変更が禁止されます。アサーションをこの状態にすることはできません。
DISABLE NOVALIDATE 制約またはアサーションはチェックされず、必ずしもtrueであるとはかぎりません。

制約の状態について学習するには、関連項目: Oracle AI Database SQL言語リファレンスを参照してください。

データベースが制約およびアサーションの妥当性チェックを行うタイミング

あらゆる制約とアサーションは、遅延不可(デフォルト)または遅延可能状態のいずれかにいます。この状態によって、Oracle AI Databaseが妥当性を確認するためにどの時点制約またはアサーションをチェックしますかが決まります。

次の図は、遅延可能制約とアサーションのオプションを示しています。

図3: 遅延可能制約とアサーションのオプション

画像cncpt313.gifの説明

遅延不可能な制約とアサーション

遅延不可制約では、Oracle AI Databaseは、制約またはアサーションの妥当性チェックをトランザクションの最後まで延期することはありません。かわりに、データベースでは各文の最後で制約またはアサーションをチェックします。制約またはアサーションに違反している場合、その文はロールバックします。

たとえば、employees.last_name列用に遅延不可のNOT NULL制約が存在します。セッションが姓のない行を挿入しようとすると、NOT NULL制約に違反しているため、データベースはただちに文をロールバックします。行は挿入されません。

遅延可能制約とアサーション

遅延可能制約またはアサーションにより、トランザクションでSET CONSTRAINT句を使用して、COMMIT文が発行されるまでこの制約またはアサーションのチェックを遅延できます。制約またはアサーションに違反している可能性があるデータベースを変更する場合、この設定によって、変更がすべて完了するまで制約またはアサーションを事実上に無効にできます。

データベースが遅延可能制約またはアサーションをチェックする時点に関して、デフォルト動作を設定できます。次の属性のいずれかを指定できます。

employees.last_nameに対する遅延可能なNOT NULL制約がINITIALLY DEFERREDに設定されているとします。ユーザーは100個のINSERT文を含むトランザクションを作成し、その一部にはlast_nameとしてNULL値があります。ユーザーがコミットしようとすると、データベースは100個すべての文をロールバックします。ただし、この制約がINITIALLY IMMEDIATEに設定されている場合、データベースはトランザクションをロールバックしません。

制約によってアクションが発生する場合は、遅延制約か即時制約かに関係なく、このアクションはアクションを発生させた文の一部とみなされます。たとえば、departmentsの行を削除すると、削除された部門の行を参照するemployeesのすべての行が削除されます。この場合、employeesからの削除は、departmentsに対して実行されたDELETE文の一部とみなされます。

関連項目:制約属性とそのデフォルト値の詳細は、『Oracle AI Database SQL言語リファレンス』を参照してください。

制約およびアサーション・チェックの例

次の例では、Oracle AI Databaseで制約とアサーションのチェックをいつ実行するかを示します。

次のようなものがあるとします。

例: 親キー値が存在しない時点での外部キー列での値の挿入

この例では、employees表に最初の行を挿入する場合を考えます。現在は行が存在しないため、manager_id列の値がemployee_id列の既存の値を参照できない場合に行を入力する方法を考えなくてはなりません。

次の可能性が考えられます。

デフォルト値は、文の解析前にINSERT文の一部として組み込まれます。このため、デフォルトの列値はすべての整合性制約チェックの対象になります。

例: すべての外部キー値および親キー値の更新

この例では、自己参照型制約によって、employeesのmanager_id列のエントリがemployee_id列の値に依存します。

会社が買収された場合です。この買収に伴い、すべての従業員番号の現在の設定値に5000を加算して、新しい会社の従業員番号と調和させる必要があります。次の図に示すように、一部の従業員は管理職でもあります。

図4: 更新前のemployees表

画像cncpt058.gifの説明

管理職番号は従業員番号でもあるため、管理職番号にも5000を加算する必要があります。次のSQL文を実行すると値を更新できます。

UPDATE employees SET employee_id = employee_id + 5000,
  manager_id = manager_id + 5000;

制約は、各manager_id値がemployee_id値と一致するかどうかを検証するように定義されていますが、データベースでは文の完了後に制約チェックが効率的に実行されるため、前述の文は有効です。図7-5に、データベースでは、制約をチェックする前に、SQL文全体のアクションが実行されていることを示します。

図5: 制約チェック

画像cncpt059.gifの説明

この項の例は、INSERT文とUPDATE文を実行した場合の制約チェックのメカニズムを示していますが、データベースでは同じメカニズムがすべてのタイプのDML文に使用されます。同じメカニズムが、自己参照型制約のみでなく、すべてのタイプの制約に使用されます。ノート: ビューまたはシノニムに対する処理は、実表に定義されている整合性制約に従います。

例: すべてのマネージャが同じ部門に事務員を持つ必要がある

この例では、すべてのマネージャが同じ部門に担当者がいることを確認するアサーションを作成します。

この例では、最初に事務員を挿入し、次にマネージャを挿入する必要があります。複数の行挿入を実行する場合、制約と同様に、各INSERT文の実行後にアサーションが検証されます。このアサーションをDEFERRABLEに設定して、最初にマネージャを挿入し、次に事務員を挿入できるようにすることができます。検証は、各INSERT文ではなくCOMMITで行われます。

CREATE ASSERTION manager_has_clerk check
(NOT EXISTS
  (SELECT 'manager without clerk'
   FROM   employees m
   WHERE  m.job_id = 'ST_MAN'
     AND  NOT EXISTS
            (SELECT 'a clerk in same department'
             FROM   employees c
             WHERE  c.job_id = 'ST_CLERK'
               AND  c.department_id = m.department_id)));