web-dev-qa-db-ja.com

スクリプトからすべての外部キーを削除しても機能しないのはなぜですか?

SQL Server 2008 R2ボックスでsysadmin権限を持っています。すべての外部キーを削除して、テストインポートの後で必要になったときにそれらを再追加できるスクリプトを見つけました。したがって、「Alter Table [ParentTable] Drop Constraint FK_Name」...というメッセージが合計23個のキーで表示されるため、構文エラーなしで以下のコードを実行しますが、サーバーまたはDBとテーブルを更新すると、各テーブルのキーノードを展開しても表示されますか?なぜそれを落とさないのですか?また、テスト目的で再度実行する場合に備えて、永続的なテーブルに変換したり、スクリプトをストアドプロシージャに配置したりする必要がありますか?アドバイスをお願いします。

「Pinal Dave」が投稿した「Swastik Mishra」の次のスクリプトを使用しました http://blog.sqlauthority.com/2014/04/11/sql-server-drop-all-the-foreign-key- constraint-in-database-create-all-the-foreign-key-constraint-in-database /

    SET NOCOUNT ON
DECLARE @table TABLE(
RowId INT PRIMARY KEY IDENTITY(1, 1),
ForeignKeyConstraintName NVARCHAR(200),
ForeignKeyConstraintTableSchema NVARCHAR(200),
ForeignKeyConstraintTableName NVARCHAR(200),
ForeignKeyConstraintColumnName NVARCHAR(200),
PrimaryKeyConstraintName NVARCHAR(200),
PrimaryKeyConstraintTableSchema NVARCHAR(200),
PrimaryKeyConstraintTableName NVARCHAR(200),
PrimaryKeyConstraintColumnName NVARCHAR(200)
)
INSERT INTO @table(ForeignKeyConstraintName, ForeignKeyConstraintTableSchema,     ForeignKeyConstraintTableName, ForeignKeyConstraintColumnName)
SELECT
U.CONSTRAINT_NAME,
U.TABLE_SCHEMA,
U.TABLE_NAME,
U.COLUMN_NAME
FROM
INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
ON U.CONSTRAINT_NAME = C.CONSTRAINT_NAME
WHERE
C.CONSTRAINT_TYPE = 'FOREIGN KEY'
UPDATE @table SET
PrimaryKeyConstraintName = UNIQUE_CONSTRAINT_NAME
FROM
@table T
INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS R
ON T.ForeignKeyConstraintName = R.CONSTRAINT_NAME
UPDATE @table SET
PrimaryKeyConstraintTableSchema = TABLE_SCHEMA,
PrimaryKeyConstraintTableName = TABLE_NAME
FROM @table T
INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS C
ON T.PrimaryKeyConstraintName = C.CONSTRAINT_NAME
UPDATE @table SET
PrimaryKeyConstraintColumnName = COLUMN_NAME
FROM @table T
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE U
ON T.PrimaryKeyConstraintName = U.CONSTRAINT_NAME
--SELECT * FROM @table
--DROP CONSTRAINT:
SELECT
'
ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' +      ForeignKeyConstraintTableName + ']
DROP CONSTRAINT ' + ForeignKeyConstraintName + '

GO’
FROM
@table
–ADD CONSTRAINT:
SELECT
‘
ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' +   ForeignKeyConstraintTableName + ']
ADD CONSTRAINT ‘ + ForeignKeyConstraintName + ‘ FOREIGN KEY(‘ +   ForeignKeyConstraintColumnName + ‘) REFERENCES [' + PrimaryKeyConstraintTableSchema + ']. [' + PrimaryKeyConstraintTableName + '](‘ + PrimaryKeyConstraintColumnName + ‘)

GO’
FROM
@table
GO
3
Shayma Ahmad

これがより良いスクリプトです。

  1. awful INFORMATION_SCHEMA views は使用しません。特に、これらのビューは外部キーを一意の制約に対して公開しません。明示的な主キー制約に対してのみ。
  2. GOはT-SQL内に配置されません。これは、コマンドを動的に実行する場合は機能しません(GOはT-SQLではなくSSMSなどのインタラクティブツールのバッチ区切り文字であるため)キーワード)。
  3. 一重引用符の代わりにアポストロフィが正しくコピーされていません(')。
  4. 複数列の外部キー制約を扱います(現在のコードは、すべての外部キーが単一列に対してのみ定義されていると想定しています)。

残りは私のブログ投稿 グループ化された連結の4つの実用的な使用例 から取られています。スクリプト#4です。


ドロップは簡単です。 sys.foreign_keysからALTER TABLEコマンドの単純なリストを作成するだけです(名前付けパターンに一致する、または特定のスキーマ内に存在する参照テーブルにスコープを制限するために使用できるコメントアウトされたフィルターも追加しました)。

DECLARE @drop NVARCHAR(MAX) = N'';

SELECT @drop += N'
ALTER TABLE ' + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) 
    + ' DROP CONSTRAINT ' + QUOTENAME(fk.name) + ';'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS ct ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs ON ct.[schema_id] = cs.[schema_id];
-- WHERE fk.referenced_object_id IN 
-- (SELECT [object_id] FROM sys.tables WHERE name LIKE N'%some pattern%')
-- WHERE fk.referenced_schema_id IN 
-- (SELECT [schema_id] FROM sys.schemas WHERE name = N'some_schema')

PRINT @drop;

まだ実行しないでください!もちろん、まだ存在している間にCREATEコマンドを生成する必要があります。作成はもう少し複雑です。ほとんどの場合、列は1つだけですが、制約の両側に列のリストを生成する必要があります(複数列の状況では、グループ化された連結が実際に役立ちます)。

DECLARE @create NVARCHAR(MAX) = N'';

SELECT @create += N'
ALTER TABLE ' 
   + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) 
   + ' ADD CONSTRAINT ' + QUOTENAME(fk.name) 
   + ' FOREIGN KEY (' + STUFF((SELECT ',' + QUOTENAME(c.name)
    FROM sys.columns AS c 
    INNER JOIN sys.foreign_key_columns AS fkc 
    ON fkc.parent_column_id = c.column_id
    AND fkc.parent_object_id = c.[object_id]
    WHERE fkc.constraint_object_id = fk.[object_id]
    ORDER BY fkc.constraint_column_id 
    FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'')
  + ') REFERENCES ' + QUOTENAME(rs.name) + '.' + QUOTENAME(rt.name)
  + '(' + STUFF((SELECT ',' + QUOTENAME(c.name)
    FROM sys.columns AS c 
    INNER JOIN sys.foreign_key_columns AS fkc 
    ON fkc.referenced_column_id = c.column_id
    AND fkc.referenced_object_id = c.[object_id]
    WHERE fkc.constraint_object_id = fk.[object_id]
    ORDER BY fkc.constraint_column_id 
    FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'') + ');'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS rt -- referenced table
  ON fk.referenced_object_id = rt.[object_id]
INNER JOIN sys.schemas AS rs ON rt.[schema_id] = rs.[schema_id]
INNER JOIN sys.tables AS ct -- constraint table
  ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs ON ct.[schema_id] = cs.[schema_id];
--WHERE rt.name LIKE N'%some pattern%'
--WHERE rs.name = N'some_schema'

PRINT @create;

出力に満足したら(PRINTは8Kに制限されているため、コマンドが切り捨てられているように見える可能性があることに注意してください)、これを最後に追加して、もう一度実行します。

EXEC sp_executesql @drop;

-- drop and re-create the table here, whatever that needs to entail

EXEC sp_executesql @create;
15
Aaron Bertrand