web-dev-qa-db-ja.com

SSMSのSETオプションを使用した奇妙な動作

SQL Server 2014 CU1でのインデックス付きビューの作成に対するさまざまなSETオプションの影響を調査しています。次のコード:

  1. sETオプションが本来あるべきものであることを保証します
  2. テーブルを作成します
  3. テーブルに基づいてビューを作成します
  4. ビューにインデックスを作成します
  5. レコードをビューに挿入します(SETオプションが正しくないと失敗します)

期待どおりに動作します。ただし、各SETオプションを意図的に誤った値に設定したセクションのコメントを外すと、CREATE INDEXステートメント(スクリプトで以前が発生します)が失敗し、QUOTED_IDENTIFIERの値が間違っていると表示されます。

SSMS 2012および2014でテストしました。これはどのように行うことができますか?

USE tempdb;

-- ensure correct SET options for indexed view creation
-- http://msdn.Microsoft.com/en-us/library/ms191432.aspx
SET ANSI_NULLS  ON;
SET ANSI_PADDING ON;
SET ANSI_WARNINGS ON;
SET ARITHABORT ON;
SET CONCAT_NULL_YIELDS_NULL ON;
SET NUMERIC_ROUNDABORT OFF;
SET QUOTED_IDENTIFIER ON;

IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.VIEWS
            WHERE TABLE_NAME = 'v1'
            AND TABLE_SCHEMA = 'dbo')
    DROP VIEW dbo.v1;
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES
            WHERE TABLE_NAME = 't1'
            AND TABLE_SCHEMA = 'dbo')
    DROP TABLE t1;
CREATE TABLE dbo.t1(c1 int);
GO
CREATE VIEW dbo.v1 WITH SCHEMABINDING AS SELECT c1 FROM dbo.t1;
GO
CREATE UNIQUE CLUSTERED INDEX i1 ON dbo.v1(c1);

---- make SET options the opposite of what is required
--SET ANSI_NULLS    OFF;
--SET ANSI_PADDING  OFF;
--SET ANSI_WARNINGS OFF;
--SET ARITHABORT    OFF;
--SET CONCAT_NULL_YIELDS_NULL   OFF;
--SET NUMERIC_ROUNDABORT    ON;
--SET QUOTED_IDENTIFIER OFF;

INSERT INTO dbo.v1(c1) VALUES(1);

DROP VIEW dbo.v1;
DROP TABLE dbo.t1;

動的SQLでそれを回避し、予期されるエラーメッセージを取得できます。

メッセージ1934、レベル16、状態1、行32のINSERTは、次のSETオプションの設定が正しくないため失敗しました: 'QUOTED_IDENTIFIER' ...

-- make SET options the opposite of what is required
EXECUTE ('SET ANSI_NULLS    OFF;
SET ANSI_PADDING    OFF;
SET ANSI_WARNINGS   OFF;
SET ARITHABORT  OFF;
SET CONCAT_NULL_YIELDS_NULL OFF;
SET NUMERIC_ROUNDABORT  ON;
SET QUOTED_IDENTIFIER   OFF;
INSERT INTO dbo.v1(c1) VALUES(1);');

しかし、なぜしなければならないのですか?

4
Colin Daley

スクリプト内のSETステートメントの中で、SET QUOTED_IDENTIFIERは、実行時ではなく解析時に処理されるという点で特別です。

From SETステートメント(Transact-SQL) (私の強調):

SETステートメントを使用する際の考慮事項

  • SET FIPS_FLAGGER、SET OFFSETS、SET PARSEONLY、およびSET QUOTED_IDENTIFIERを除くすべてのSETステートメントは、実行時または実行時に実装されます。これらのステートメントは実装されます解析時。

SET QUOTED_IDENTIFIER(Transact-SQL) で確認済み:

備考

[…]

SET QUOTED_IDENTIFIERは解析時に設定されます。 […]

したがって、あなたの場合、QUOTED_IDENTIFIERは解析時にリセットされるため、CREATE INDEXが実行されるまでにOFFになります。エンジンは予想通りそれについて不平を言います。

これを解決するには、動的SQLを使用する必要はありません。CREATEINDEXステートメントの直後にGO行を配置して、後続のSETとは異なるバッチにすることで十分であり、それらとは別に解析されます:

…

CREATE UNIQUE CLUSTERED INDEX i1 ON dbo.v1(c1);

GO

-- make SET options the opposite of what is required
SET ANSI_NULLS    OFF;
SET ANSI_PADDING  OFF;
SET ANSI_WARNINGS OFF;
SET ARITHABORT    OFF;
SET CONCAT_NULL_YIELDS_NULL   OFF;
SET NUMERIC_ROUNDABORT    ON;
SET QUOTED_IDENTIFIER OFF;

…

ただし、 SETステートメント(Transact-SQL) には以下も含まれることに注意してください(強調は私のものです)。

SETステートメントを使用する際の考慮事項

[…]

  • 計算列またはインデックス付きビューでインデックスを作成および操作する場合、SETオプションARITHABORT、CONCAT_NULL_YIELDS_NULL、QUOTED_IDENTIFIER、ANSI_NULLS、ANSI_PADDING、およびANSI_WARNINGSをONに設定する必要があります。オプションNUMERIC_ROUNDABORTはOFFに設定する必要があります。

    これらのオプションのいずれかが必要な値に設定されていない場合、インデックス付きビューまたは計算された列にインデックスを持つテーブルでのINSERT、UPDATE、DELETE、DBCC CHECKDB、およびDBCC CHECKTABLEアクションは失敗します。SQL Serverは、正しく設定されていないすべてのオプションを一覧表示するエラーを発生させます。また、SQL Serverは、計算列またはビューのインデックスが存在しないかのように、これらのテーブルまたはインデックス付きビューのSELECTステートメントを処理します。

つまり、コメント化されていないSETステートメントは、CREATE INDEXだけでなくINSERTでもスクリプトを中断します。

4
Andriy M