KB956718 - 修正: MERGE ステートメントがクラスタリング キーの一部ではない一意のキー列を更新し、SQL Server 2008 の更新ソースとして 1 つの行がある場合、外部キー制約が適用されないことがあります

適用先
SQL Server 2008

バグ #: 50003167 (SQL 修正プログラム)

SQL がリリースされた後にリリースされたビルドのマスター リストの詳細については、以下のサポート技術情報番号をクリックしてください。

957826 SQL Server 2008 以降にリリースされた SQL Server 2008 ビルドおよび SQL Server 2005 Service Pack 2 以降にリリースされた SQL Server 2005 ビルドの詳細情報を参照する場所

現象

Microsoft SQL Server 2008 では、次の条件に該当する場合、外部キー制約が適用されないことがあります。

  • MERGE ステートメントが発行されます。
  • 更新プログラムのターゲット列には、非クラスター化一意インデックスがあります。

次のような状況を想定します。 このステートメントは、Table1 という名前のテーブルの Column1 という名前の一意のカラムを更新します。 Table1 は、 Table2 という名前のテーブルからの外部キー制約によって参照されます。

その結果、 Table1 の行が変更される本来は行われないときに変更されます。 さらに、 Table2 には、 Table1 への参照がダングリングされている行が含まれます。

この問題は、次の条件に該当する場合に発生します。

  • Table1 の参照先 Column1 列は、Table1 のクラスタリング キーの一部ではありません。

  • Column1 列に割り当てることができる値は 1 つだけです。 たとえば、次のいずれかのシナリオが発生します。

    • 差し込み元は 1 行のデータです。 たとえば、マージ ソースは次の select ステートメントのいずれかからのものです。

      • select <ConstantValues>
        
      • select <Parameters>
        

      注: 最も可能性の高いシナリオはこのシナリオです。

    • マージ ソースは、実際には 1 行のデータです。 たとえば、マージ ソースは次の select ステートメントのいずれかからのものです。

      • select <ColumnName> from <TableName> where <TableName>.<ColumnName> = 1
        

        注 <TableName>.<ColumnName> は、クエリ オプティマイザによって一意の値であることが認識されています。

      • select top 1 <ColumnName> from <TableName>
        
    • マージ ソースとマージ ターゲットの間の結合には、1 つの行が更新されることを保証する述語があります。

    • update 句は、マージ ソースに関係なく、 Column1 列を定数値に設定します。

  • 表 2 の外部キー制約の [On Update Cascade] オプションが有効になっていません。

注: MERGE ステートメントを使用して、外部キー制約によって参照される非クラスター化一意インデックスを持つ列を更新する場合は、この修正プログラムを適用することをお勧めします。

解決策

この問題の解決方法は、累積的な更新プログラム1で初めてリリースされました。 SQL Server 2008用のこの累積的な更新プログラムパッケージを入手する方法の詳細についてはをクリックして以下「サポート技術情報」(Microsoft サポート技術情報)資料を参照。

956717 SQL Server 2008 用の累積的な更新プログラム パッケージ 1

注 : ビルドは累積的であるため、新しくリリースされたパッケージには、それ以前の SQL Server 2008 更新プログラムのリリースに含まれていたすべての修正プログラムおよびセキュリティ更新プログラムが含まれています。 この修正プログラムが含まれている最新リリースの修正の適用を検討することを推奨します。 詳細については、次のマイクロソフト サポート技術情報番号をクリックしてください。

956909 SQL Server 2008 のリリース以降にリリースされた SQL Server 2008 のビルド

回避策

修正プログラム パッケージを適用すると、この問題は解決されます。 「現象」で説明されているシナリオで MERGE ステートメントを使用し、修正プログラムを適用しない場合は、次の手順に従ってこの問題を解決します。

  1. マージ ソースの値がクエリ内でインライン化されるのではなく、テーブル、一時テーブル、またはテーブル変数に含まれるように、MERGE ステートメントを書き換えます。

  2. トレース フラグ 8790 を使用。 このトレース フラグは、広範囲更新プランと呼ばれる一種のプランをオプティマイザーに強制的に使用させます。 ワイドアップデートプランでは問題ありません。 この手順は、すべての DML ステートメントのパフォーマンス リスクを伴います。 したがって、アプリケーションの変更が不可能な場合を除き、この手順を使用しないでください。

次の Transact-SQL スクリプトは、この修正プログラムを適用できない場合にスクリプトを変更してこの問題を解決する方法の 1 つです。

たとえば、次のようなスクリプトがあるとします。

use tempdb;

drop table sale, product;
create table product(pno int not null primary key, name char(30), pAlternateKey char(6) not null unique);
create table sale(sno int not null primary key, pAlternateKey char(6) not null references product(pAlternateKey));
insert product values(1, 'Office Chair', 'ochair');
insert sale values(1, 'ochair')

-- No violation of foreign key constraint is detected. However, one should be.
merge into product
using (select 'Office Chair2' as name, 1 as pno, 'oxx' as pAlternateKey) as src
on product.pno = src.pno
when matched then
   update set product.pAlternateKey = src.pAlternateKey, 
              product.name = src.name
when not matched then
   insert values(src.pno, src.name, src.pAlternateKey);

次のようにスクリプトを変更します。

insert product values(1, 'Office Chair', 'ochair');
insert sale values(1, 'ochair')
-- A foreign key constraint violation is detected, and the update fails.
declare @source table 
   (name nchar(30), pno int, pAlternateKey nchar(30));
insert into @source values('Office Chair2',1,'oxx');

merge into product
using @source as src
on product.pno = src.pno
when matched then
   update set product.pAlternateKey = src.pAlternateKey, 
              product.name = src.name
when not matched then
   insert values(src.pno, src.name, src.pAlternateKey);

状態

Microsoft は、これが "適用対象" セクションに記載されている Microsoft 製品の問題であることを確認しました。

追加情報

変更されるファイル、およびこの「サポート技術情報」 (Microsoft サポート技術情報) の資料に記載されている修正プログラムが含まれる累積的な更新プログラム パッケージを適用するための必要条件の関連情報を参照するには、以下の「サポート技術情報」 (Microsoft サポート技術情報) をクリックしてください。

956717 SQL Server 2008 用の累積的な更新プログラム パッケージ 1

参考資料

SQL Server 2008 のリリース以降に利用可能なビルドの一覧の詳細については、以下のサポート技術情報番号をクリックしてください。

956909 SQL Server 2008 のリリース以降にリリースされた SQL Server 2008 のビルド

SQL Server の増分サービス モデルの関連情報を参照するには、以下のサポート技術情報番号をクリックしてください。

935897 報告された問題に対する修正プログラムを提供する SQL Server チームの増分サービス モデル (ISM) について

SQL Server の更新プログラムの命名方式の関連情報を参照するには、以下のサポート技術情報番号をクリックしてください。

822499 Microsoft SQL Server ソフトウェア更新プログラム パッケージの新しい名前付けスキーマ

ソフトウェア更新プログラムに関する用語の関連情報を参照するには、以下のサポート技術情報番号をクリックしてください。

824684 Microsoft のソフトウェア更新プログラムの説明で使用される一般的な用語の解説

SQL Server 2008 の非クラスター化インデックス

SQL Server 2008 の非クラスター化インデックスの詳細については、次の MSDN (Microsoft Developer Network) Web サイトを参照してください。

https://msdn.microsoft.com/library/ms179325(sql.100).aspx