<?xml version="1.0" encoding="x-sjis"?>
<?xml:stylesheet href="AprilTechNetStyle.xsl" type="text/xsl" ?>
<chp><ss1><st type="U">データの整合性とビジネス ルールの設定</st></ss1>

<p>　データの整合性を設定すると、データベース内のデータの質が保証されます。テーブルのプランを作成する際には、列の有効な値を識別することと、その列のデータの整合性の設定方法を決定することの 2 つのステップが重要です。データの整合性は次の 4 種類に分類され、いくつかの方法で設定可能です。

<nl/></p>
<tbl ms="TW" gu="0" in="120" cw="3000 3000 " wd="6120">
<th>
<row><c>整合性のタイプ</c>
<c>設定オプション</c>
</row>
</th><tby>

<row><c></c>
</row>
<row><c>実体</c>
<c>PRIMARY KEY 制約</c>
</row>
<row><c></c>
<c>UNIQUE 制約</c>
</row>
<row><c></c>
<c>IDENTITY プロパティ</c>
</row>
<row><c>ドメイン</c>
<c>ドメイン DEFAULT 定義</c>
</row>
<row><c></c>
<c>FOREIGN KEY 制約</c>
</row>
<row><c></c>
<c>CHECK 制約</c>
</row>
<row><c></c>
<c>NULL 値の許容</c>
</row>
<row><c>参照</c>
<c>ドメイン DEFAULT 定義</c>
</row>
<row><c></c>
<c>FOREIGN KEY 制約</c>
</row>
<row><c></c>
<c>CHECK 制約</c>
</row>
<row><c></c>
<c>NULL 値の許容</c>
</row>
<row><c>ユーザー定義</c>
<c>CREATE TABLE でのすべての列制約およびテーブル制約</c>
</row>
<row><c></c>
<c>ストアド プロシージャ</c>
</row>

<row><c></c>
</row>
<row><c></c>
<c>トリガ</c>
</row>
</tby></tbl>

<ss2><st type="U">実体の整合性</st></ss2>

<p>　実体の整合性は、行を特定のテーブルの一意な実体として定義します。実体の整合性は、テーブルの識別子列または主キーの整合性を、インデックス、UNIQUE 制約、PRIMARY KEY 制約または IDENTITY プロパティによって設定します。

<nl/></p>
<h>■ 制約に名前を付ける</h>

<p>　制約には常に明示的に名前を付けることをお勧めします。名前を付けずにおくと、Oracle と SQL Server は異なる名前付け規則を使って制約に既定の名前を付けます。名前付け規則の違いによって、移行処理が不必要に煩雑になる場合があります。制約は名前で削除する必要があるため、制約を削除または無効にするときに違いが出てきます。制約に明示的に名前を付けるための構文は、Oracle と SQL Server とで同一です。

<nl/></p>
<ex>
<nl/>
<type f="courier">　CONSTRAINT constraint_name</type></ex>
<br/>

<h>■ 主キーと一意な列</h>

<p>　SQL-92 標準では、主キーのすべての値は一意でなければならず、主キーが NULL 値であってはなりません。Oracle と SQL Server ではいずれも、PRIMARY KEY 制約または UNIQUE 制約が定義されている場合に常に一意なインデックスを自動的に作成することによって、一意性を保証しています。さらに、主キーの列は NOT NULL として自動的に定義されます。主キーは 1 つのテーブルに 1 つしか認められません。

<nl/>　デフォルトの状態では、SQL Server のクラスタ化インデックスは主キー用に作成されますが、非クラスタ化インデックスを要求することもできます。Oracle では、制約を削除または無効にすることでインデックスを削除できますが、SQL Server では制約を削除しない限りインデックスを削除することはできません。

<nl/>　どちらの RDBMS でも、UNIQUE 制約を使用して代替キーを定義できます。複数の UNIQUE 制約を任意のテーブルに対して定義できます。UNIQUE 制約の列には、NULL 値が許容されます。SQL Server では、特に指定しない限り、デフォルトの状態では非クラスタ化インデックスが作成されます。

<nl/>　アプリケーションの移行時、完全に一意なキー（単一または複数の列インデックス）の場合、SQL Server では、NULL 値を持つことができるのは 1 行だけですが、Oracle では、NULL 値を持つ行が何行あってもかまわないことに注意してください。

<nl/></p>
<tbl ms="TW" gu="0" in="120" cw="3000 3000 " wd="6120">
<th>
<row><c>Oracle</c>
<c>SQL Server</c>
</row>
</th><tby>

<row><c></c>
</row>
<row><c>CREATE TABLE DEPT_ADMIN.DEPT</c>
<c>CREATE TABLE</c>
</row>
<row><c>(DEPT VARCHAR2(4) NOT NULL,</c>
<c>USER_DB.DEPT_ADMIN.DEPT</c>
</row>
<row><c>DNAME VARCHAR2(30) NOT NULL,</c>
<c>(DEPT VARCHAR(4) NOT NULL,</c>
</row>
<row><c>CONSTRAINT DEPT_DEPT_PK</c>
<c>DNAME VARCHAR(30) NOT NULL,</c>
</row>
<row><c>　PRIMARY KEY (DEPT)</c>
<c>CONSTRAINT DEPT_DEPT_PK</c>
</row>
<row><c>　USING INDEX TABLESPACE</c>
<c>　PRIMARY KEY CLUSTERED (DEPT),</c>
</row>
<row><c>　USER_DATA</c>
<c>CONSTRAINT DEPT_DNAME_UNIQUE</c>
</row>
<row><c>　PCTFREE 0 STORAGE (</c>
<c>　UNIQUE NONCLUSTERED (DNAME)</c>
</row>
<row><c>　INITIAL 10K NEXT 10K</c>
<c>)</c>
</row>
<row><c>　MINEXTENTS 1 MAXEXTENTS</c>
<c></c>
</row>
<row><c>　UNLIMITED),</c>
<c></c>
</row>
<row><c>CONSTRAINT DEPT_DNAME_UNIQUE</c>
<c></c>
</row>
<row><c>　UNIQUE (DNAME)</c>
<c></c>
</row>
<row><c>　USING INDEX TABLESPACE USER_DATA</c>
<c></c>
</row>
<row><c>　PCTFREE 0 STORAGE (</c>
<c></c>
</row>
<row><c>　INITIAL 10K NEXT 10K</c>
<c></c>
</row>
<row><c>　MINEXTENTS 1 MAXEXTENTS</c>
<c></c>
</row>
<row><c>　UNLIMITED)</c>
<c></c>
</row>

<row><c></c>
</row>
<row><c>)</c>
<c></c>
</row>
</tby></tbl>

<h>■ 制約の追加と削除</h>

<p>　制約を無効にすることで、データベースのパフォーマンスが向上し、データ レプリケーション プロセスが効率的になります。たとえば、リモート サイトでテーブル データをリビルドまたはレプリケートする場合、制約のチェックを繰り返す必要はありません。データ整合性は、データがテーブルに入力された時点でチェックされるからです。Oracle アプリケーションで（PRIMARY KEY と UNIQUE 以外の）制約を有効または無効にしている場合は、ALTER TABLE ステートメントで CHECK オプションと WITH NOCHECK オプションを使用することによって、SQL Server で同じプロセスを簡単に達成できます。

<nl/>　この処理を次の図で示します。

<nl/></p>
<art id="p465" type="bmp" pos="C"/>


<p>　SQL Server では、ALL キーワードと NOCHECK 句を使用して、すべてのテーブルの制約を無効にできます。

<nl/>　Oracle アプリケーションで CASCADE オプションを使用して PRIMARY KEY 制約または UNIQUE 制約を無効または削除している場合は、プログラム コードの一部を書き直さなければならないことがあります。CASCADE オプションでは、親および関連する子の両方の整合性制約を無効にしたり、削除したりするからです。

<nl/>　構文の例を次に示します。

<nl/></p>
<ex>
<nl/>
<type f="courier">　DROP CONSTRAINT DEPT_DEPT_PK CASCADE</type></ex>


<p>　SQL Server のアプリケーションでは、子の制約を先に削除してから親の制約を削除するように修正する必要があります。たとえば、DEPT テーブルの PRIMARY KEY 制約を削除するには、STUDENT.MAJOR 列と CLASS.DEPT 列の外部キーを削除する必要があります。構文の例を次に示します。

<nl/></p>
<ex>
<nl/>
<type f="courier">　ALTER TABLE STUDENT</type></ex>

<ex>
<nl/>
<type f="courier">　DROP CONSTRAINT STUDENT_MAJOR_FK</type></ex>
<ex>
<nl/>
<type f="courier">　ALTER TABLE CLASS</type></ex>
<ex>
<nl/>
<type f="courier">　DROP CONSTRAINT CLASS_DEPT_FK</type></ex>
<ex>
<nl/>
<type f="courier">　ALTER TABLE DEPT</type></ex>

<ex>
<nl/>
<type f="courier">　DROP CONSTRAINT DEPT_DEPT_PK</type></ex>
<br/>

<p>　制約の追加と削除に使用する ALTER TABLE 構文は、Oracle と SQL Server とでほぼ同じです。

<nl/></p>
<h>■ 連続した数値の生成</h>

<p>　Oracle のアプリケーションで SEQUENCES を使用している場合には、Microsoft SQL Server の IDENTITY プロパティを利用するように簡単に変更することができます。

<nl/></p>
<tbl ms="TW" gu="0" in="120" cw="3000 3000 " wd="6120">
<th>
<row><c>カテゴリ</c>
<c>SQL Server の IDENTITY</c>
</row>
</th><tby>

<row><c></c>
</row>
<row><c>構文</c>
<c>CREATE TABLE new_employees</c>
</row>
<row><c></c>
<c>(Empid int IDENTITY(1,1),</c>
</row>
<row><c></c>
<c>　Employee_Name varchar(60),</c>
</row>
<row><c></c>
<c>　CONSTRAINT Emp_PK PRIMARY KEY(Empid)</c>
</row>
<row><c></c>
<c>)</c>
</row>
<row><c></c>
<c>If increment interval is 5:</c>
</row>
<row><c></c>
<c>CREATE TABLE new_employees</c>
</row>
<row><c></c>
<c>(Empid int IDENTITY(1,5),</c>
</row>
<row><c></c>
<c>　Employee_Name varchar(60),</c>
</row>
<row><c></c>
<c>　CONSTRAINT Emp_PK PRIMARY KEY(Empid)</c>
</row>
<row><c></c>
<c>)</c>
</row>
<row><c>テーブル 1 つあたりの ID 列数</c>
<c>1</c>
</row>
<row><c>NULL 値の許容</c>
<c>許容せず</c>
</row>
<row><c>既定の制約値の使用</c>
<c>使用不可</c>
</row>
<row><c>一意性の設定</c>
<c>あり</c>
</row>
<row><c>INSERT ステートメント、SELECT INTO ステートメント、または一括コピーが終了すると、現在の最大 ID 番号を照会します。</c>
<c>@@IDENTITY（関数）</c>
</row>
<row><c>ID 列の作成時に指定された seed の値を返します。</c>
<c>IDENT_SEED(&apos;<I>table_name</I>&apos;)</c>
</row>
<row><c>ID 列の作成時に指定されたインクリメント値を返します。</c>
<c>IDENT_INCR(&apos;<I>table_name</I>&apos;)</c>
</row>
<row><c>SELECT 構文</c>
<c>SELECT ステートメント、INSERT ステートメント、UPDATE ステートメント、DELETE ステートメントに IDENTITY プロパティを含む列を参照する場合に、列名の代わりにキーワード IDENTITYCOL を使用できます。</c>
</row>
</tby></tbl>


<p>　IDENTITY プロパティは、テーブル内の各行を一意に識別する一連番号を自動的に作成できますが、識別子列はテーブルごとに作成されるため、他のテーブルでは識別子列に同じ値が生成されてもかまいません。IDENTITY プロパティは、識別子列が定義されたテーブル内で一意でありさえすればよいからです。データベース全体あるいはネットワーク接続された世界中のあらゆるコンピュータ上の各データベースで一意な識別子列を生成しなければならない場合は、ROWGUIDCOL プロパティと uniqueidentifier データ型、NEWID 関数を使用してください。SQL Server は、グローバル一意識別子列を使用してマージ レプリケーションを行い、複数のテーブルに渡って行が一意に識別されるようにしてください。

<nl/>　識別子列の作成と修正の詳細については、SQL Server の［Books Online］を参照してください。

<nl/></p>
<ss2><st type="U">ドメイン整合性</st></ss2>

<p>　ドメイン整合性は、エントリがその列のエントリとして妥当であることを保証します。ドメイン整合性は、（データ型によって）値の型を、（CHECK 制約によって）値の形式を、（REFERENCE 制約と CHECK 制約によって）値の範囲を制限することによって保つことができます。

<nl/></p>
<h>■ DEFAULT 制約と CHECK 制約</h>

<p>　既定値は Oracle では列のプロパティとして扱われますが、SQL Server では制約として扱われます。SQL Server の DEFAULT 制約には、定数値、引数を取らない組み込み関数（ニラディック関数）または NULL を含むことができます。

<nl/>　Oracle の DEFAULT 列のプロパティを簡単に移行するには、SQL Server の列レベルで DEFAULT 制約を定義し、制約名を適用しないようにしてください。SQL Server は、DEFAULT 制約ごとに一意な名前を生成します。

<nl/>　CHECK 制約を定義するための構文は、Oracle でも SQL Server でも同じです。検索条件は論理式として評価される必要があり、サブクエリを含むことはできません。列レベルの CHECK 制約は、制約された列だけを参照でき、テーブル レベルの CHECK 制約は、制約されたテーブルの列だけを参照できます。1 つのテーブルに対して複数の CHECK 制約を定義できます。SQL Server の構文では、1 つの CREATE TABLE ステートメントで列 レベルの制約を 1 つしか定義することができませんが、列のそれぞれの制約は複数の条件を持つことができます。

<nl/>　修正後の CREATE TABLE ステートメントをテストするには、SQL Sever で構文のみを解析する方法が一番です。エラーがあればすべて結果ペインに表示されます。制約構文の詳細については、SQL Server の［Books Online］を参照してください。

<nl/></p>
<tbl ms="TW" gu="0" in="120" cw="3000 3000 " wd="6120">
<th>
<row><c>Oracle</c>
<c>SQL Server</c>
</row>
</th><tby>

<row><c></c>
</row>
<row><c>CREATE TABLE STUDENT</c>
<c>CREATE TABLE USER_DB.STUDENT</c>
</row>
<row><c>　_ADMIN.STUDENT(</c>
<c>　_ADMIN.STUDENT(</c>
</row>
<row><c>SSN CHAR(9) NOT NULL,</c>
<c>SSN CHAR(9) NOT NULL,</c>
</row>
<row><c>FNAME VARCHAR2(12) NULL,</c>
<c>FNAME VARCHAR(12) NULL,</c>
</row>
<row><c>LNAME VARCHAR2(20) NOT NULL,</c>
<c>LNAME VARCHAR(20) NOT NULL,</c>
</row>
<row><c>GENDER CHAR(1) NOT NULL</c>
<c>GENDER CHAR(1) NOT NULL</c>
</row>
<row><c>　CONSTRAINT</c>
<c>　CONSTRAINT STUDENT_GENDER_CK</c>
</row>
<row><c>　STUDENT_GENDER_CK</c>
<c>　CHECK (GENDER IN (&apos;M&apos;,&apos;F&apos;)),</c>
</row>
<row><c>　CHECK (GENDER IN (&apos;M&apos;,&apos;F&apos;)),</c>
<c>MAJOR VARCHAR(4)</c>
</row>
<row><c>MAJOR VARCHAR2(4)</c>
<c>　DEFAULT &apos;Undc&apos; NOT NULL,</c>
</row>
<row><c>　DEFAULT &apos;Undc&apos; NOT NULL,</c>
<c>BIRTH_DATE DATETIME NULL,</c>
</row>
<row><c>BIRTH_DATE DATE NULL,</c>
<c>TUITION_PAID NUMERIC(12,2) NULL,</c>
</row>
<row><c>TUITION_PAID NUMBER(12,2) NULL,</c>
<c>TUITION_TOTAL NUMERIC(12,2) NULL,</c>
</row>
<row><c>TUITION_TOTAL NUMBER(12,2) NULL,</c>
<c>START_DATE DATETIME NULL,</c>
</row>
<row><c>START_DATE DATE NULL,</c>
<c>GRAD_DATE DATETIME NULL,</c>
</row>
<row><c>GRAD_DATE DATE NULL,</c>
<c>LOAN_AMOUNT NUMERIC(12,2) NULL,</c>
</row>
<row><c>LOAN_AMOUNT NUMBER(12,2) NULL,</c>
<c>DEGREE_PROGRAM CHAR(1)</c>
</row>
<row><c>DEGREE_PROGRAM CHAR(1)</c>
<c>　DEFAULT &apos;U&apos; NOT NULL</c>
</row>
<row><c>　DEFAULT &apos;U&apos; NOT NULL</c>
<c>　CONSTRAINT STUDENT_DEGREE_CK</c>
</row>
<row><c>　CONSTRAINT</c>
<c>　　CHECK</c>
</row>
<row><c>　STUDENT_DEGREE_CK     CHECK</c>
<c>　　(DEGREE_PROGRAM IN (&apos;U&apos;, &apos;M&apos;,</c>
</row>
<row><c>　(DEGREE_PROGRAM IN (&apos;U&apos;, &apos;M&apos;, &apos;P&apos;,</c>
<c>　　&apos;P&apos;,&apos;D&apos;)),</c>
</row>
<row><c>　&apos;D&apos;)),</c>
<c>...</c>
</row>

<row><c></c>
</row>
<row><c>...</c>
<c></c>
</row>
</tby></tbl>


<p>　ユーザー定義の規則と既定値について、下位互換性を維持する目的で SQL Server の規則と既定値に関する構文を残してありますが、新規のアプリケーション開発では CHECK 制約と DEFAULT 制約を使用することをお勧めします。詳細については、SQL Server の［Books Online］を参照してください。

<nl/></p>
<h>■ NULL と NOT NULL</h>

<p>　SQL Server でも Oracle でも、列の制約を作成して NULL 値を許容するか否かを設定します。CREATE TABLE ステートメントまたは ALTER TABLE ステートメントで指定しない限り、Oracle の表の列はデフォルトで NULL になります。SQL Server では、列の定義で使用したデータ型が NULL 値を許すかどうかは、データベースやセッションの設定に優先することがあります。

<nl/>　（Oracle であるか SQL Server であるかとは無関係に）すべての SQL スクリプトで列ごとに NULL と NOT NULL を両方とも明示的に定義することをお勧めします。具体的な方法については、テーブル作成のサンプル スクリプト Oratable.sql と Sstable.sql を参照してください。明示的に指定しなければ、列で NULL 値を許すかどうかは、次のルールに従います。

<nl/></p>
<tbl ms="TW" gu="0" in="120" cw="3000 3000 " wd="6120">
<th>
<row><c>NULL の設定</c>
<c>説明</c>
</row>
</th><tby>

<row><c></c>
</row>
<row><c>列がユーザー定義のデータ型で定義されている</c>
<c>SQL Server は、データ型の作成時に指定された NULL 値を許容するかどうかの設定を使用します。データ型に NULL 値を許すかどうかのデフォルトの設定を調べるには、sp_help システム ストアド プロシージャを使用します。</c>
</row>
<row><c>列がシステム提供のデータ型で定義されている</c>
<c>システム提供のデータ型にオプションが 1 つしかない場合は、これが優先されます。bit 型は NOT NULL としてだけ定義できます。</c>
</row>
<row><c></c>
<c>セッションの設定が ON（SET で設定）の場合は、次のようになります。</c>
</row>
<row><c></c>
<c>ANSI_NULL_DFLT_ON が ON の場合は、NULL が割り当てられます。</c>
</row>
<row><c></c>
<c>ANSI_NULL_DFLT_OFF が ON の場合は、NOT NULL が割り当てられます。</c>
</row>
<row><c></c>
<c>データベースの設定が構成（sp_dboption システム ストアド プロシージャで変更）されている場合は、次のようになります。</c>
</row>
<row><c></c>
<c>
<l2>
<li/>
<p>ANSI null デフォルトが true の場合は NULL が割り当てられます。</p>
<c></c>

<li/>
<p>ANSI null デフォルトが false の場合は NOT NULL が割り当てられます。</p>
</l2></c></row>
<row><c></c>
</row>
<row><c>NULL/NOT NULL 未定義</c>
<c>明示的に定義されない場合（ANSI_NULL_DFLT オプションのいずれも設定されない）は、セッションは変更されず、データベースはデフォルト（ANSI null デフォルトが false）に設定され、SQL Server はこれに NOT NULL を割り当てます。</c>
</row>
</tby></tbl>

<ss2><st type="U">参照整合性</st></ss2>

<p>　参照整合性の制約の定義に使用される構文を次に示します。

<nl/></p>
<tbl ms="TW" gu="0" in="120" cw="2000 2000 2000 " wd="6120">
<th>
<row><c>制約</c>
<c>Oracle</c>
<c>SQL Server</c>
</row>
</th><tby>

<row><c></c>
</row>
<row><c>PRIMARY KEY</c>
<c>[CONSTRAINT</c>
<c>[CONSTRAINT</c>
</row>
<row><c></c>
<c>constraint_name]</c>
<c>constraint_name]</c>
</row>
<row><c></c>
<c>PRIMARY KEY (col_name [,</c>
<c>PRIMARY KEY [CLUSTERED |</c>
</row>
<row><c></c>
<c>col_name2 [..., col_name16]])</c>
<c>NONCLUSTERED] (col_name [,</c>
</row>
<row><c></c>
<c>[USING INDEX</c>
<c>col_name2 [..., col_name16]])</c>
</row>
<row><c></c>
<c>storage_parameters]</c>
<c>[ON segment_name]</c>
</row>
<row><c></c>
<c></c>
<c>[NOT FOR REPLICATION]</c>
</row>
<row><c>UNIQUE</c>
<c>[CONSTRAINT</c>
<c>[CONSTRAINT</c>
</row>
<row><c></c>
<c>constraint_name]</c>
<c>constraint_name]</c>
</row>
<row><c></c>
<c>UNIQUE (col_name [,</c>
<c>UNIQUE [CLUSTERED |</c>
</row>
<row><c></c>
<c>col_name2 [..., col_name16]])</c>
<c>NONCLUSTERED](col_name [,</c>
</row>
<row><c></c>
<c>[USING INDEX</c>
<c>col_name2 [..., col_name16]])</c>
</row>
<row><c></c>
<c>storage_parameters]</c>
<c>[ON segment_name]</c>
</row>
<row><c></c>
<c></c>
<c>[NOT FOR REPLICATION]</c>
</row>
<row><c>FOREIGN KEY</c>
<c>[CONSTRAINT</c>
<c>[CONSTRAINT</c>
</row>
<row><c></c>
<c>constraint_name]</c>
<c>constraint_name]</c>
</row>
<row><c></c>
<c>[FOREIGN KEY (col_name [,</c>
<c>[FOREIGN KEY (col_name [,</c>
</row>
<row><c></c>
<c>col_name2 [...,</c>
<c>col_name2 [...,</c>
</row>
<row><c></c>
<c>col_name16]])]</c>
<c>col_name16]])]</c>
</row>
<row><c></c>
<c>REFERENCES</c>
<c>REFERENCES [owner.]ref_table</c>
</row>
<row><c></c>
<c>[owner.]ref_table [</c>
<c>[(ref_col [, ref_col2 [...,</c>
</row>
<row><c></c>
<c>(ref_col [, ref_col2 [...,</c>
<c>ref_col16]])]</c>
</row>
<row><c></c>
<c>ref_col16]])]</c>
<c>[NOT FOR REPLICATION]</c>
</row>

<row><c></c>
</row>
<row><c></c>
<c>[ON DELETE CASCADE]</c>
<c></c>
</row>

<row><c></c>
</row>
<row><c>DEFAULT</c>
<c>列のプロパティには制約がない</c>
<c>[CONSTRAINT</c>
</row>
<row><c></c>
<c>DEFAULT (constant_expression)</c>
<c>constraint_name]</c>
</row>
<row><c></c>
<c></c>
<c>DEFAULT {constant_expression</c>
</row>
<row><c></c>
<c></c>
<c>| niladic-function | NULL}</c>
</row>
<row><c></c>
<c></c>
<c>[FOR col_name]</c>
</row>
<row><c></c>
<c></c>
<c>[NOT FOR REPLICATION]</c>
</row>
<row><c></c>
<c></c>
<c>CHECK</c>
</row>
<row><c></c>
<c></c>
<c>[CONSTRAINT constraint_name]</c>
</row>
<row><c></c>
<c></c>
<c>CHECK (expression)</c>
</row>
<row><c></c>
<c></c>
<c>[CONSTRAINT constraint_name]</c>
</row>
<row><c></c>
<c></c>
<c>CHECK [NOT FOR</c>
</row>

<row><c></c>
</row>
<row><c></c>
<c></c>
<c>REPLICATION] (expression)</c>
</row>
</tby></tbl>


<p>　NOT FOR REPLICATION 句は、レプリケーション時に、列レベルの制約、FOREIGN KEY 制約、CHECK 制約が設定されるのを防止するために使用されます。

<nl/></p>
<h>■ 外部キー</h>

<p>　外部キーを定義する規則は、各 RDBMS で似ています。外部キーの句で指定した列の数とデータ型は、REFERENCES 句と一致する必要があります。この列に入力された NULL でない値は、REFERENCES 句で定義してあるテーブルと列の中に存在する必要があります。参照されるテーブルの列は、PRIMARY KEY 制約または UNIQUE の制約を持っている必要があります。

<nl/>　SQL Server の制約は、同じデータベース内のテーブルしか参照できません。複数のデータベースにまたがる参照整合性を得るには、テーブル ベースのトリガを使用してください。

<nl/>　Oracle と SQL Server は両方とも自己参照テーブルをサポートします。これは、同一のテーブルの 1 つ以上の列に対して参照（外部キー）を置くことができるテーブルです。たとえば、CLASS テーブルの 列 prereq は、CLASS テーブルの 列 ccode を参照し、コースの前提として有効なコース コードを入力することができます。

<nl/>　Oracle ではカスケード削除とカスケード更新を CASCADE DELETE 句で定義できますが、SQL Server ではテーブル トリガで同じ機能が得られます。詳細については、この章の「SQL 言語サポート」を参照してください。

<nl/></p>
<ss2><st type="U">ユーザー定義の整合性</st></ss2>

<p>　ユーザー定義の整合性は、他の整合性のカテゴリに当てはまらない特定のビジネス ルールを定義することを可能にします。

<nl/></p>
<h>■ ストアド プロシージャ</h>

<p>　ユーザーが指定するパラメータを受け取り、またそれを返す SQL Server のストアド プロシージャを作成するには、CREATE PROCEDURE ステートメントを使用します。ストアド プロシージャは現在のデータベース内でのみ作成できますが、一時ストアド プロシージャだけは例外です。ストアド プロシージャを作成するための Oracle と SQL Server での構文を次の表に示します。

<nl/></p>
<tbl ms="TW" gu="0" in="120" cw="3000 3000 " wd="6120">
<th>
<row><c>Oracle</c>
<c>SQL Server</c>
</row>
</th><tby>

<row><c></c>
</row>
<row><c>CREATE OR REPLACE PROCEDURE</c>
<c>CREATE PROC[EDURE] procedure_name</c>
</row>
<row><c>[user.]procedure</c>
<c>　[;number]</c>
</row>
<row><c>　[(argument [IN | OUT] datatype</c>
<c>　　[</c>
</row>
<row><c>　[, argument [IN | OUT] datatype]</c>
<c>　　{@parameter data_type} [VARYING]</c>
</row>
<row><c>{IS | AS} block</c>
<c>　　[= default] [OUTPUT]</c>
</row>
<row><c></c>
<c>　　]</c>
</row>
<row><c></c>
<c>　[,...n]</c>
</row>
<row><c></c>
<c>[WITH</c>
</row>
<row><c></c>
<c>　{ RECOMPILE   | ENCRYPTION |</c>
</row>
<row><c></c>
<c>　　RECOMPILE, ENCRYPTION} ]</c>
</row>
<row><c></c>
<c>[FOR REPLICATION]</c>
</row>
<row><c></c>
<c>AS</c>
</row>

<row><c></c>
</row>
<row><c></c>
<c>　sql_statement [...n]</c>
</row>
</tby></tbl>


<p>　SQL Server では、ローカル一時プロシージャの場合は <I>procedure_name</I> の前にシャープ記号（#）を 1 つ付加（<I>#procedure_name</I>）し、グローバル一時プロシージの場合は <I>procedure_name</I> の前にシャープ記号を 2 つ付加（<I>##procedure_name</I>）して、tempdb データベース内で作成します。

<nl/>　ローカル一時プロシージャは、それを作成したユーザーだけが使用できます。ローカル一時プロシージャの実行権限を他のユーザーに与えることはできません。ローカル一時プロシージャは、ユーザー セッションの終了時に自動的に削除されます。

<nl/>　グローバル一時プロシージャの場合は、SQL Server のすべてのユーザーが利用できます。グローバル一時プロシージャを作成すると、ユーザー全員がそれにアクセスでき、権限を明示的に取り消すことはできません。グローバル一時プロシージャは、そのプロシージャを使用する最後のユーザー セッションの終了時に削除されます。

<nl/>　SQL Server のストアド プロシージャは、32 レベルまでネストすることができます。ネストレベルは、呼び出されたプロシージャが実行を開始すると 1 つ増え、呼び出されたプロシージャが実行を終了すると 1 つ減ります。

<nl/>　次の例は、Transact-SQL ストアド プロシージャを使用してどのように Oracle PL/SQL パッケージ関数を置き換えるかを示したものです。SQL Server では、カーソルを使用せずに結果のセットを SELECT ステートメントから直接返すことができるため、Transact-SQL を使う方がはるかに簡単です。

<nl/></p>
<tbl ms="TW" gu="0" in="120" cw="3000 3000 " wd="6120">
<th>
<row><c>Oracle</c>
<c>SQL Server</c>
</row>
</th><tby>

<row><c></c>
</row>
<row><c>CREATE OR REPLACE PACKAGE</c>
<c>CREATE PROCEDURE</c>
</row>
<row><c>　STUDENT_ADMIN.P1 AS ROWCOUNT</c>
<c>STUDENT_ADMIN.SHOW_</c>
</row>
<row><c>　NUMBER :=0;</c>
<c>RELUCTANT_STUDENTS</c>
</row>
<row><c>　CURSOR C1 RETURN</c>
<c>AS SELECT FNAME+&apos;&apos; +LNAME+&apos;,</c>
</row>
<row><c>　STUDENT%ROWTYPE;</c>
<c>　social security number&apos;+ SSN+&apos;</c>
</row>
<row><c>　FUNCTION</c>
<c>　is not enrolled in any classes!&apos;</c>
</row>
<row><c>　SHOW_RELUCTANT_STUDENTS</c>
<c>FROM STUDENT_ADMIN.STUDENT S</c>
</row>
<row><c>(WORKVAR OUT VARCHAR2) RETURN</c>
<c>WHERE NOT EXISTS</c>
</row>
<row><c>NUMBER;</c>
<c>　(SELECT &apos;X&apos; FROM</c>
</row>
<row><c>END P1;</c>
<c>　STUDENT_ADMIN.GRADE G</c>
</row>
<row><c>/</c>
<c>　WHERE G.SSN=S.SSN)</c>
</row>
<row><c></c>
<c>ORDER BY SSN</c>
</row>
<row><c>CREATE OR REPLACE PACKAGE BODY</c>
<c>RETURN@@ROWCOUNT</c>
</row>
<row><c>　STUDENT_ADMIN.P1 AS CURSOR C1</c>
<c>GO</c>
</row>
<row><c>　RETURN STUDENT%ROWTYPE IS</c>
<c></c>
</row>
<row><c>　SELECT * FROM</c>
<c></c>
</row>
<row><c>　STUDENT_ADMIN.STUDENT</c>
<c></c>
</row>
<row><c>　WHERE NOT EXISTS</c>
<c></c>
</row>
<row><c>　(SELECT &apos;X&apos; FROM</c>
<c></c>
</row>
<row><c>　STUDENT_ADMIN.GRADE</c>
<c></c>
</row>
<row><c>　WHERE</c>
<c></c>
</row>
<row><c>　GRADE.SSN=STUDENT.SSN) ORDER</c>
<c></c>
</row>
<row><c>　BY SSN;</c>
<c></c>
</row>
<row><c>FUNCTION SHOW_RELUCTANT_STUDENTS</c>
<c></c>
</row>
<row><c>　(WORKVAR OUT VARCHAR2) RETURN</c>
<c></c>
</row>
<row><c>　NUMBER IS</c>
<c></c>
</row>
<row><c>　WORKREC STUDENT%ROWTYPE;</c>
<c></c>
</row>
<row><c>　BEGIN</c>
<c></c>
</row>
<row><c>　IF NOT C1%ISOPEN THEN OPEN C1;</c>
<c></c>
</row>
<row><c>　　ROWCOUNT :=0;</c>
<c></c>
</row>
<row><c>　ENDIF;</c>
<c></c>
</row>
<row><c>　FETCH C1 INTO WORKREC;</c>
<c></c>
</row>
<row><c>　IF (C1%NOTFOUND) THEN</c>
<c></c>
</row>
<row><c>　　CLOSE C1;</c>
<c></c>
</row>
<row><c>　　ROWCOUNT :=0;</c>
<c></c>
</row>
<row><c>　ELSE</c>
<c></c>
</row>
<row><c>　　WORKVAR := WORKREC.FNAME||&apos;</c>
<c></c>
</row>
<row><c>　　&apos;||WORKREC.LNAME||</c>
<c></c>
</row>
<row><c>　　&apos;, social security number</c>
<c></c>
</row>
<row><c>　　&apos;||WORKREC.SSN||&apos; is not enrolled</c>
<c></c>
</row>
<row><c>　　in any classes!&apos;;</c>
<c></c>
</row>
<row><c>　　ROWCOUNT := ROWCOUNT + 1;</c>
<c></c>
</row>
<row><c>　ENDIF;</c>
<c></c>
</row>
<row><c>RETURN(ROWCOUNT);</c>
<c></c>
</row>
<row><c>　EXCEPTION</c>
<c></c>
</row>
<row><c>　WHEN OTHERS THEN</c>
<c></c>
</row>
<row><c>　IF C1%ISOPEN THEN CLOSE C1;</c>
<c></c>
</row>
<row><c>　　ROWCOUNT :=0;</c>
</row>
<row><c>　ENDIF;</c>
</row>
<row><c>　RAISE_APPLICATION_ERROR</c>
</row>
<row><c>　(-20001,SQLERRM);</c>
</row>
<row><c>END SHOW_RELUCTANT_STUDENTS;</c>
</row>
<row><c>END P1;</c>
</row>

<row><c></c>
</row>
<row><c>/</c>
</row>
</tby></tbl>


<p>　SQL Server には、Oracle のパッケージや関数のような構成はありません。また、ストアド プロシージャを作成するための CREATE OR REPLACE オプションもありません。

<nl/></p>
<h>■ ストアド プロシージャの実行の遅延</h>

<p>　SQL Server には、ステートメント ブロック、ストアド プロシージャまたはトランザクションを起動する、時刻、時間またはイベントを指定する WAITFOR ステートメントがあります。これは、Oracle の dbms_lock.sleep と等しい Transact-SQL です。

<nl/></p>

<p>　WAITFOR {DELAY &apos;time&apos; | TIME &apos;time&apos;}</p>

<l2>
<li/>
<p>DELAY

<nl/>最長 24 時間までの指定時間が経過するまで SQL Server に待機を指示します。</p>

<li/>
<p>&apos;<I>time</I>&apos;
<nl/>待機する時間の長さです。<I>time</I> は、datetime データに適合するいずれかの形式で指定することも、ローカル変数として指定することもできます。日付を指定することはできません。したがって、datetime 値の 日付の部分は無視されます。</p>

<li/>
<p>TIME

<nl/>指定時刻になるまで SQL Server に待機を指示します。
<ex>
<nl/>
<type f="courier">BEGIN</type></ex>
<nl/>　　WAITFOR TIME &apos;22:20&apos;
<nl/>　　EXECUTE update_all_stats<ex>
<nl/>
<type f="courier">END</type></ex>
</p>
</l2>
<h>■ ストアド プロシージャのパラメータの指定</h>

<p>　ストアド プロシージャ内のパラメータを指定するには、次の構文を使用します。

<nl/></p>
<tbl ms="TW" gu="0" in="120" cw="3000 3000 " wd="6120">
<th>
<row><c>Oracle</c>
<c>SQL Server</c>
</row>
</th><tby>

<row><c><I>Varname datatype</I> DEFAULT &lt;<I>value</I>&gt;;</c>
<c>{@<I>parameter data_type</I>}[VARYING] [= <I>default</I>][OUTPUT］</c>
</row>
<row></row>
</tby></tbl>

<h>■ トリガ</h>

<p>　Oracle と SQL Server のどちらにもトリガはありますが、機能には若干の違いがあります。

<nl/></p>
<tbl ms="TW" gu="0" in="120" cw="2000 2000 2000 " wd="6120">
<th>
<row><c>説明</c>
<c>Oracle</c>
<c>SQL Server</c>
</row>
</th><tby>

<row><c></c>
</row>
<row><c>テーブル 1 つあたりのトリガ数</c>
<c>無制限</c>
<c>無制限</c>
</row>
<row><c>INSERT、UPDATE、DELETE の前に実行されるトリガ</c>
<c>あり</c>
<c>なし</c>
</row>
<row><c>INSERT、UPDATE、DELETE の後に実行されるトリガ</c>
<c>あり</c>
<c>あり</c>
</row>
<row><c>ステートメント レベルのトリガ</c>
<c>あり</c>
<c>あり</c>
</row>
<row><c>行レベルのトリガ</c>
<c>あり</c>
<c>なし</c>
</row>
<row><c>実行前の制約チェック</c>
<c>トリガが無効にならない限り、チェックあり。</c>
<c>チェックあり。これはデータ変換サービスのオプションでもある。</c>
</row>
<row><c>UPDATE トリガまたは DELETE トリガで古い値または前の値を参照する</c>
<c>:old</c>
<c>DELETED.column</c>
</row>
<row><c>INSERT トリガで新しい値を参照する</c>
<c>:new</c>
<c>INSERTED.column</c>
</row>

<row><c></c>
</row>
<row><c>トリガを無効にする</c>
<c>ALTER TRIGGER</c>
<c>データ変換サービスのオプション</c>
</row>
</tby></tbl>


<p>　DELETED と INSERTED は、トリガ ステートメントに対して SQL Server が作成する論理（概念的）テーブルです。この論理テーブルは、トリガを定義し、行の値がユーザー操作によって変更された場合の元の値と新しい値を保持するテーブルと構造的には似ています。これらのテーブルは、行レベルの変更を Transact-SQL でトラッキングします。その機能は Oracle の行レベルのトリガと同様です。INSERT ステートメント、UPDATE ステートメントまたは DELETE ステートメントを SQL Server で実行すると、トリガ テーブルに行が追加されると同時に、INSERTED テーブルと DELETED テーブルにも行が追加されます。

<nl/>　INSERTED テーブルおよび DELETED テーブルは、トリガ テーブルと同じもので、列名やデータ型も同じになります。たとえば、GRADE テーブルにトリガを設定すると、INSERTED テーブルと DELETED テーブルは次のような構造になります。

<nl/></p>
<tbl ms="TW" gu="0" in="120" cw="2000 2000 2000 " wd="6120">
<th>
<row><c>GRADE</c>
<c>INSERTED</c>
<c>DELETED</c>
</row>
</th><tby>

<row><c></c>
</row>
<row><c>SSN CHAR(9)</c>
<c>SSN CHAR(9)</c>
<c>SSN CHAR(9)</c>
</row>
<row><c>CCODE VARCHAR(4)</c>
<c>CCODE VARCHAR(4)</c>
<c>CCODE VARCHAR(4)</c>
</row>

<row><c></c>
</row>
<row><c>GRADE VARCHAR(2)</c>
<c>GRADE VARCHAR(2)</c>
<c>GRADE VARCHAR(2)</c>
</row>
</tby></tbl>


<p>　INSERTED テーブルと DELETED テーブルをトリガによって検査し、どのタイプのトリガを行うべきか判断することができます。INSERTED テーブルには INSERT ステートメントと UPDATE ステートメントを使用します。DELETED テーブルには DELETE ステートメントと UPDATE ステートメントを使用します。

<nl/>　UPDATE ステートメントは、INSERTED テーブルと DELETED テーブルの両方を使用します。UPDATE を実行すると常に古い行が削除され、新たな行が追加されるからです。この結果、UPDATE を実行すると、INSERTED テーブルの行は常に DELETED テーブルの行と同じものになります。

<nl/>　次の例では、INSERTED テーブルと DELETED テーブルを使用して PL/SQL の行レベルのトリガを置き換えます。完全外部結合では、両方のテーブルのすべての行が結果に含まれます。

<nl/></p>
<tbl ms="TW" gu="0" in="120" cw="3000 3000 " wd="6120">
<th>
<row><c>Oracle</c>
<c>SQL Server</c>
</row>
</th><tby>

<row><c></c>
</row>
<row><c>CREATE TRIGGER</c>
<c>CREATE TRIGGER</c>
</row>
<row><c>　STUDENT_ADMIN.TRACK_GRADES</c>
<c>　STUDENT_ADMIN.TRACK_GRADES</c>
</row>
<row><c>AFTER</c>
<c>ON STUDENT_ADMIN.GRADE</c>
</row>
<row><c>INSERT OR UPDATE OR DELETE</c>
<c>FOR INSERT, UPDATE, DELETE</c>
</row>
<row><c>ON STUDENT_ADMIN.GRADE</c>
<c>AS</c>
</row>
<row><c>FOR EACH ROW</c>
<c>INSERT INTO GRADE_HISTORY(</c>
</row>
<row><c>BEGIN</c>
<c>　TABLE_USER, ACTION_DATE,</c>
</row>
<row><c>INSERT INTO GRADE_HISTORY(</c>
<c>　OLD_SSN, OLD_CCODE, OLD_GRADE</c>
</row>
<row><c>　TABLE_USER, ACTION_DATE,</c>
<c>　NEW_SSN, NEW_CCODE,    NEW_GRADE)</c>
</row>
<row><c>　OLD_SSN, OLD_CCODE,</c>
<c>SELECT USER, GETDATE(),</c>
</row>
<row><c>　OLD_GRADE, NEW_SSN,</c>
<c>　OLD.SSN, OLD.CCODE,</c>
</row>
<row><c>　NEW_CCODE, NEW_GRADE)</c>
<c>　OLD.GRADE,</c>
</row>
<row><c>VALUES (USER, SYSDATE,</c>
<c>　NEW.SSN,</c>
</row>
<row><c>　:OLD.SSN, :OLD.CCODE,</c>
<c>　NEW.CCODE,</c>
</row>
<row><c>　:OLD.GRADE,</c>
<c>　NEW.GRADE</c>
</row>
<row><c>　:NEW.SSN,</c>
<c>FROM INSERTED NEW FULL OUTER JOIN</c>
</row>
<row><c>　:NEW.CCODE,</c>
<c>　DELETED OLD ON NEW.SSN = OLD.SSN</c>
</row>
<row><c>　:NEW.GRADE),</c>
<c></c>
</row>

<row><c></c>
</row>
<row><c>END;</c>
<c></c>
</row>
</tby></tbl>


<p>　トリガは現在のデータベースでしか作成することができませんが、他のデータベース内のオブジェクトを参照することはできます。トリガを修飾する所有者名を指定するときは、テーブル名を同じ方法で修飾します。

<nl/>　トリガは 32 段階のレベルまでネストすることができます。あるトリガが別のトリガを持つテーブルを変更した場合、2 番目のトリガがアクティブになり、次に 3 番目のトリガを呼び出すという具合に、順にアクティブになります。このトリガのチェインで無限ループが発生すると、ネスト レベルの上限を超えたことになり、トリガはキャンセルされます。また、テーブルの 1 つの列に対して更新トリガを実行することで他の列が更新される場合は、この更新トリガは一度しかアクティブになりません。

<nl/>　SQL Server の宣言参照整合性（DRI）ではデータベース間の参照整合性は得られません。データベース間の参照整合性が必要な場合はトリガを使用してください。

<nl/>　次の挙げるステートメントは、Transact-SQL のトリガでは使用できません。

<nl/></p>

<l2>
<li/>
<p>CREATE ステートメント（DATABASE、TABLE、INDEX、PROCEDURE、DEFAULT、RULE、TRIGGER、SCHEMA、VIEW）
</p>

<li/>
<p>DROP ステートメント（TRIGGER、INDEX、TABLE、PROCEDURE、DATABASE、VIEW、DEFAULT、RULE）</p>

<li/>
<p>ALTER ステートメント（DATABASE、TABLE、VIEW、PROCEDURE、TRIGGER）</p>

<li/>
<p>TRUNCATE TABLE</p>

<li/>
<p>GRANT、REVOKE、DENY</p>

<li/>
<p>UPDATE STATISTICS</p>

<li/>
<p>RECONFIGURE</p>

<li/>
<p>UPDATE STATISTICS</p>

<li/>
<p>RESTORE DATABASE、RESTORE LOG</p>

<li/>
<p>LOAD LOG、DATABASE</p>

<li/>
<p>DISK ステートメント
</p>

<li/>
<p>SELECT INTO（テーブルが作成されてしまうため）
</p>
</l2>

<p>　トリガの詳細については、SQL Server の［Books Online］を参照してください。

<nl/></p>

</chp>
