60

FlatFilesからデータベース内の既存のテーブルにいくつかのテーブルのデータを置き換えるSSISパッケージを実行しています。

私のパッケージはテーブルを切り捨ててから、新しいデータを挿入します。SSISパッケージを実行すると、外部キーが原因で例外が発生します。

制約を無効にして、インポートを実行してから、再度有効にすることはできますか?

4

9 に答える 9

104

外部キー制約を無効にするには:

DECLARE @sql nvarchar(max) = N'';

;WITH x AS 
(
  SELECT DISTINCT obj = 
      QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.' 
    + QUOTENAME(OBJECT_NAME(parent_object_id)) 
  FROM sys.foreign_keys
)
SELECT @sql += N'ALTER TABLE ' + obj + N' NOCHECK CONSTRAINT ALL;
' FROM x;

EXEC sys.sp_executesql @sql;

再度有効にするには:

DECLARE @sql nvarchar(max) = N'';

;WITH x AS 
(
  SELECT DISTINCT obj = 
      QUOTENAME(OBJECT_SCHEMA_NAME(parent_object_id)) + '.' 
    + QUOTENAME(OBJECT_NAME(parent_object_id)) 
  FROM sys.foreign_keys
)
SELECT @sql += N'ALTER TABLE ' + obj + N' WITH CHECK CHECK CONSTRAINT ALL;
' FROM x;

EXEC sys.sp_executesql @sql;

ただし、テーブルを切り捨てることはできません。正しい順序でテーブルから削除する必要があります。それらを切り捨てる必要がある場合は、制約を完全に削除して、それらを再作成する必要があります。これは、外部キー制約がすべて単純な単一列の制約である場合は簡単ですが、複数の列が含まれている場合は間違いなくより複雑になります。

これがあなたが試すことができるものです。これをSSISパッケージの一部にするには、SSISパッケージの実行中にFK定義を保存する場所が必要です(これをすべて1つのスクリプトで実行することはできません)。したがって、一部のユーティリティデータベースで、テーブルを作成します。

CREATE TABLE dbo.PostCommand(cmd nvarchar(max));

次に、データベースに、これを行うストアドプロシージャを作成できます。

DELETE other_database.dbo.PostCommand;

DECLARE @sql nvarchar(max) = N'';

SELECT @sql += N'ALTER TABLE ' 
   + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id))
   + '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id)) 
   + ' ADD CONSTRAINT ' + fk.name + ' FOREIGN KEY (' 
   + STUFF((SELECT ',' + 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(''), 
    TYPE).value(N'./text()[1]', 'nvarchar(max)'), 1, 1, N'')
+ ') REFERENCES ' + 
QUOTENAME(OBJECT_SCHEMA_NAME(fk.referenced_object_id))
+ '.' + QUOTENAME(OBJECT_NAME(fk.referenced_object_id))
+ '(' + 
STUFF((SELECT ',' + 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(''), 
    TYPE).value(N'./text()[1]', N'nvarchar(max)'), 1, 1, N'') + ');
' FROM sys.foreign_keys AS fk
WHERE OBJECTPROPERTY(parent_object_id, 'IsMsShipped') = 0;

INSERT other_database.dbo.PostCommand(cmd) SELECT @sql;

IF @@ROWCOUNT = 1
BEGIN
  SET @sql = N'';

  SELECT @sql += N'ALTER TABLE ' + QUOTENAME(OBJECT_SCHEMA_NAME(fk.parent_object_id))
    + '.' + QUOTENAME(OBJECT_NAME(fk.parent_object_id)) 
    + ' DROP CONSTRAINT ' + fk.name + ';
  ' FROM sys.foreign_keys AS fk;

  EXEC sys.sp_executesql @sql;
END

これで、SSISパッケージが終了すると、次のような別のストアドプロシージャを呼び出す必要があります。

DECLARE @sql nvarchar(max);

SELECT @sql = cmd FROM other_database.dbo.PostCommand;

EXEC sys.sp_executesql @sql;

削除ではなく切り捨てを行うためだけにこれらすべてを実行している場合は、ヒットを取得して削除を実行することをお勧めします。たぶん、ログの影響を最小限に抑えるために、一括ログ回復モデルを使用します。一般に、このソリューションが、正しい順序で削除を使用するよりもはるかに高速になるかどうかはわかりません。

2014年に、これに関するより詳細な投稿をここに公開しました。

于 2012-07-24T22:01:43.007 に答える
49

組み込みのsp_msforeachtableストアドプロシージャを使用します。

すべての制約を無効にするには:

EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT ALL";

すべての制約を有効にするには:

EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL";

すべてのテーブルを削除するには:

EXEC sp_msforeachtable "DROP TABLE ?";
于 2014-12-17T10:57:24.327 に答える
5

http://msdn.microsoft.com/en-us/magazine/cc163442.aspx の「DisableingAllForeignKeys」セクションに適切なリファレンスがあります。

そこから着想を得て、一時テーブルを作成し、そのテーブルに制約を挿入し、制約を削除して、その一時テーブルからそれらを再適用することで、アプローチを行うことができます。ここで私が話していることは十分に言われています

 SET NOCOUNT ON

    DECLARE @temptable TABLE(
       Id INT PRIMARY KEY IDENTITY(1, 1),
       FKConstraintName VARCHAR(255),
       FKConstraintTableSchema VARCHAR(255),
       FKConstraintTableName VARCHAR(255),
       FKConstraintColumnName VARCHAR(255),
       PKConstraintName VARCHAR(255),
       PKConstraintTableSchema VARCHAR(255),
       PKConstraintTableName VARCHAR(255),
       PKConstraintColumnName VARCHAR(255)    
    )

    INSERT INTO @temptable(FKConstraintName, FKConstraintTableSchema, FKConstraintTableName, FKConstraintColumnName)
    SELECT 
       KeyColumnUsage.CONSTRAINT_NAME, 
       KeyColumnUsage.TABLE_SCHEMA, 
       KeyColumnUsage.TABLE_NAME, 
       KeyColumnUsage.COLUMN_NAME 
    FROM 
       INFORMATION_SCHEMA.KEY_COLUMN_USAGE KeyColumnUsage
          INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TableConstraints
             ON KeyColumnUsage.CONSTRAINT_NAME = TableConstraints.CONSTRAINT_NAME
    WHERE
       TableConstraints.CONSTRAINT_TYPE = 'FOREIGN KEY'

    UPDATE @temptable SET
       PKConstraintName = UNIQUE_CONSTRAINT_NAME
    FROM 
       @temptable tt
          INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS ReferentialConstraint
             ON tt.FKConstraintName = ReferentialConstraint.CONSTRAINT_NAME

    UPDATE @temptable SET
       PKConstraintTableSchema  = TABLE_SCHEMA,
       PKConstraintTableName  = TABLE_NAME
    FROM @temptable tt
       INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TableConstraints
          ON tt.PKConstraintName = TableConstraints.CONSTRAINT_NAME

    UPDATE @temptable SET
       PKConstraintColumnName = COLUMN_NAME
    FROM @temptable tt
       INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE KeyColumnUsage
          ON tt.PKConstraintName = KeyColumnUsage.CONSTRAINT_NAME


    --Now to drop constraint:
    SELECT
       '
       ALTER TABLE [' + FKConstraintTableSchema + '].[' + FKConstraintTableName + '] 
       DROP CONSTRAINT ' + FKConstraintName + '

       GO'
    FROM
       @temptable

    --Finally to add constraint:
    SELECT
       '
       ALTER TABLE [' + FKConstraintTableSchema + '].[' + FKConstraintTableName + '] 
       ADD CONSTRAINT ' + FKConstraintName + ' FOREIGN KEY(' + FKConstraintColumnName + ') REFERENCES [' + PKConstraintTableSchema + '].[' + PKConstraintTableName + '](' + PKConstraintColumnName + ')

       GO'
    FROM
       @temptable

    GO
于 2012-07-25T03:48:15.117 に答える
4

これには簡単な方法があります。

-- Disable all the constraint in database
EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all'

-- Enable all the constraint in database
EXEC sp_msforeachtable 'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all'

リファレンスSQLSERVER–データベースのすべての外部キー制約を無効にする–データベースのすべての外部キー制約を有効にする

于 2020-08-03T09:27:29.523 に答える
1

すべてのテーブル制約を無効にする

ALTER TABLE TableName NOCHECK CONSTRAINT ConstraintName

-すべてのテーブル制約を有効にします

ALTER TABLE TableName CHECK CONSTRAINT ConstraintName
于 2014-12-17T09:57:15.417 に答える
1

「.dbo」とは異なるデータベーススキーマを使用している場合、またはデータベースに複数のフィールドで構成されるPkが含まれている場合は、Carter Medlinのソリューションを使用しないでください。使用すると、データベースが損傷します。

さまざまなスキーマで作業している場合は、これを試してください(前にデータベースのバックアップを作成することを忘れないでください!):

DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
    'ALTER INDEX ALL ON ' + SCHEMA_NAME( t.schema_id) +'.'+ '['+ t.[name] + '] DISABLE;'+CHAR(13)
from  
    sys.tables t
where type='u'

select @sql = @sql +
    'ALTER INDEX ' + i.[name] + ' ON ' + SCHEMA_NAME( t.schema_id) +'.'+'[' + t.[name] + '] REBUILD;'+CHAR(13)
from  
    sys.key_constraints i
join
    sys.tables t on i.parent_object_id=t.object_id
where     i.type='PK'

exec dbo.sp_executesql @sql;
go

Fkを使用しないアクションを実行した後、

DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
    'ALTER INDEX ALL ON ' + SCHEMA_NAME( t.schema_id) +'.'+'[' +  t.[name] + '] REBUILD;'+CHAR(13)
from  
    sys.tables t
where type='u'
print @sql

exec dbo.sp_executesql @sql;
exec sp_msforeachtable "ALTER TABLE ? WITH NOCHECK CHECK CONSTRAINT ALL";
于 2018-12-12T13:39:20.743 に答える
0

SQLでsidableFKに対してクエリを実行する必要はありません。テーブルAからBへのFKがある場合は、次のことを行う必要があります。

  • テーブルAからデータを削除します
  • テーブルBからデータを削除します
  • Bにデータを挿入
  • Aにデータを挿入

制約をチェックしないように宛先に指示することもできます

ここに画像の説明を入力してください

于 2012-07-25T08:41:36.923 に答える
0

外部キーを無効にしてもテーブルを切り捨てることはできません。したがって、deleteコマンドを使用してテーブルからすべてのレコードを削除できますが、数百万のレコードで構成されるテーブルに対してdeleteコマンドを使用している場合は、パッケージに注意してください。速度が低下し、トランザクションログのサイズが大きくなり、貴重なディスク領域がいっぱいになる可能性があります。

制約を削除すると、テーブルがクリーンでないデータでいっぱいになる可能性があり、制約を再作成しようとすると、エラーが発生するため、許可されない場合があります。したがって、制約を削除する場合は、相互に正しく関連し、再作成する制約関係を満たすデータをロードしていることを確認してください。

そのため、各方法の長所と短所を慎重に検討し、要件に応じて使用してください

于 2013-10-29T06:39:33.157 に答える
-2

すべてのインデックス(すべてのfksを無効にするpkを含む)を無効にしてから、pksを再度有効にします。

DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
    'ALTER INDEX ALL ON [' + t.[name] + '] DISABLE;'+CHAR(13)
from  
    sys.tables t
where type='u'

select @sql = @sql +
    'ALTER INDEX ' + i.[name] + ' ON [' + t.[name] + '] REBUILD;'+CHAR(13)
from  
    sys.key_constraints i
join
    sys.tables t on i.parent_object_id=t.object_id
where
    i.type='PK'


exec dbo.sp_executesql @sql;
go

[データの読み込みを行います]

その後、すべてを生き返らせます...

DECLARE @sql AS NVARCHAR(max)=''
select @sql = @sql +
    'ALTER INDEX ALL ON [' + t.[name] + '] REBUILD;'+CHAR(13)
from  
    sys.tables t
where type='u'

exec dbo.sp_executesql @sql;
go
于 2018-08-01T19:24:41.630 に答える