2012-04-04 47 views
11

データベースにはANSI_NULLS OFFで作成されたテーブルがあります。これで、この表を使用してビューを作成しました。このビューにクラスタード・インデックスを追加します。既存テーブルのANSI_NULLSオプションを更新

クラスタ化されたインデックスを作成しているときに、この特定のテーブルに対してANSI_NULLがオフであるため、インデックスを作成できないというエラーが表示されます。

この表には大量のデータが含まれています。ですから、このオプションをONに変更して、データを失うことはありません。

テーブルを変更してこのオプションを変更する方法はありますか。あなたの提案をお願いします。

答えて

16

これはcross posted on Database Administratorsだったので、将来の検索ユーザーを支援するために私の回答も掲載しています。

ALTER TABLE ... SWITCHを使用してメタデータのみを変更する(つまり、すべてのデータを新しいテーブルに移行することなく)ことができます。あなたのテーブルを使用すると、IDENTITY値を再シードする必要がIDENTITY列を含む:サンプルコード

/*Create table with option off*/ 
SET ANSI_NULLS OFF; 

CREATE TABLE dbo.YourTable (X INT) 

/*Add some data*/ 
INSERT INTO dbo.YourTable VALUES (1),(2),(3) 

/*Confirm the bit is set to 0*/ 
SELECT uses_ansi_nulls, * 
FROM sys.tables 
WHERE object_id = object_id('dbo.YourTable') 

GO 

BEGIN TRY 
    BEGIN TRANSACTION; 
    /*Create new table with identical structure but option on*/ 
    SET ANSI_NULLS ON; 
    CREATE TABLE dbo.YourTableNew (X INT) 

    /*Metadata only switch*/ 
    ALTER TABLE dbo.YourTable SWITCH TO dbo.YourTableNew; 

    DROP TABLE dbo.YourTable; 

    EXECUTE sp_rename N'dbo.YourTableNew', N'YourTable','OBJECT'; 

    /*Confirm the bit is set to 1*/ 
    SELECT uses_ansi_nulls, * 
    FROM sys.tables 
    WHERE object_id = object_id('dbo.YourTable') 

    /*Data still there!*/ 
    SELECT * 
    FROM dbo.YourTable 

    COMMIT TRANSACTION; 
END TRY 

BEGIN CATCH 
    IF XACT_STATE() <> 0 
     ROLLBACK TRANSACTION; 

    PRINT ERROR_MESSAGE(); 
END CATCH; 

WARNING以下

。 SWITCH TOはID列のシードをリセットし、IDにUNIQUEまたはPRIMARY KEY制約がない場合(SQL 2014でCLUSTERED COLUMNSTOREインデックスを使用する場合など)、すぐには気づかないでしょう。 シード値を正しく設定するには、DBCC CHECKIDENT( 'dbo.YourTable'、RESEED、[reseed value])を使用する必要があります。

+0

これは元のテーブルのすべてのインデックスと制約を保持しますか? –

+0

いいえ、すべてのインデックスと制約が保持されません。 – xav

+0

@xav 'create table'にそれらを含めるとします。 –

2

残念ながら、再作成せずに行う方法はありません。 ANSI_NULLS ONで新しいテーブルを作成し、そこにすべてのデータをコピーする必要があります。

それはのようなものでなければなりません:任意の依存オブジェクトがある場合、彼らはできるだけ早くあなたがそれを名前を変更、新しいテーブルで動作します

SET ANSI_NULLS ON; 

CREATE TABLE new_MyTBL (
.... 
) 

-- stop all processes changing your data at this point 

SET IDENTITY_INSERT new_MyTBL ON 

INSERT new_MyTBL (...) -- including IDENTITY field 
SELECT ...    -- including IDENTITY field 
FROM MyTBL 

SET IDENTITY_INSERT new_MyTBL OFF 

-- alter/drop WITH SCHEMABINDING objects at this point 

EXEC sp_rename @objname = 'MyTBL', @newname = 'old_MyTBL' 
EXEC sp_rename @objname = 'new_MyTBL', @newname = 'MyTBL' 

-- alter/create WITH SCHEMABINDING objects at this point 
-- re-enable your processes 

DROP TABLE old_MyTBL  -- do that when you are sure that system works OK 

。しかし、それらのうちのいくつかがWITH SCHEMABINDINGである場合、あなたはDROPCREATEをマニュアルにする必要があります。

+0

このテーブルに関連付けられたビューがあります。では、ビューと関連するテーブルに影響を与えずに、このテーブルのデータを新しく作成したテーブルに移行する最も良い方法は何ですか? –

+0

はい、schemabindingオプションを使用してビューを作成しました。スキーマバインドを削除してクエリを実行するようにビューを変更できますか?出来ますか? –

+0

あなたのビューはインデックスに登録されていますか?それらをスキーマ結合する理由は何ですか? –

0

私は上記推奨のSWITCHオプションを試しましたが、IDをRESEEDできませんでした。なぜ私は見つけることができませんでした。

私の代わりに、次の代替アプローチを使用:

  1. あなたは
  2. はあなたが意図するテーブルを削除更新する予定表のテーブル
  3. スクリプトのテーブル定義が含まれているデータベースのデータベーススナップショットを作成します。 (データベーススナップショットが正常に作成されたことを確認してください)
  4. 手順2で取得したスクリプトからSET ANSI NULLをOFFからONに更新し、更新されたスクリプトを実行します。テーブルが再作成されました。あなたのテーブルへのデータベース・スナップショットから
  5. 移入データ: SET IDENTITY_INSERT TABLE_NAME ON INSERT INTO TABLE_NAME (PK, col1, etc.) SELECT PK, col1, etc. FROM [Database_Snapshot].dbo.TABLE_NAME SET IDENTITY_INSERT TABLE_NAME OFF
  6. 移行非クラスタ化インデックスを手動以上を使用して

(データベーススナップショットからスクリプトを取得):

  • 私は持っていませんでしたテーブル/制約名は常に同じであるため制約とキーが気になる(何も名前を変更する必要はありません)
  • 私は自分のデータのバックアップをとっています私は何も欠けていないことを再確認することができます。
  • 私はテーブルが他のテーブルで参照されている場合、テーブルを削除することは必ずしも容易ではないかもしれない実現アイデンティティ

を再シードする必要はありません。この場合、私にとってはそうではありませんでした。私は運が良かったです。

関連する問題