HaB*_*aBo 44 sql-server ssis constraints sql-server-2008
我正在运行一个SSIS包,它将从FlatFiles中的几个表的数据替换为数据库中的现有表.
我的包将截断表,然后插入新数据.当我运行我的SSIS包时,由于外键我得到一个例外.
我可以禁用约束,运行导入,然后重新启用它们吗?
Aar*_*and 81
要禁用外键约束:
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 + ' NOCHECK CONSTRAINT ALL;
' FROM x;
EXEC sp_executesql @sql;
Run Code Online (Sandbox Code Playgroud)
要重新启用:
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 + ' WITH CHECK CHECK CONSTRAINT ALL;
' FROM x;
EXEC sp_executesql @sql;
Run Code Online (Sandbox Code Playgroud)
但是,您将无法截断表,您必须按正确的顺序从中删除它们.如果需要截断它们,则需要完全删除约束,然后重新创建它们.如果外键约束都是简单的单列约束,这很容易做到,但如果涉及多个列,则肯定会更复杂.
这是你可以尝试的东西.为了使其成为SSIS包的一部分,您需要在SSIS包运行时存储FK定义的位置(您将无法在一个脚本中完成所有操作).所以在一些实用程序数据库中,创建一个表:
CREATE TABLE dbo.PostCommand(cmd NVARCHAR(MAX));
Run Code Online (Sandbox Code Playgroud)
然后在您的数据库中,您可以拥有执行此操作的存储过程:
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('.', 'nvarchar(max)'), 1, 1, '')
+ ') 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('.', 'nvarchar(max)'), 1, 1, '') + ');
' 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 sp_executesql @sql;
END
Run Code Online (Sandbox Code Playgroud)
现在,当您的SSIS包完成后,它应该调用另一个存储过程,它执行以下操作:
DECLARE @sql NVARCHAR(MAX);
SELECT @sql = cmd FROM other_database.dbo.PostCommand;
EXEC sp_executesql @sql;
Run Code Online (Sandbox Code Playgroud)
如果你只是为了能够截断而不是删除而完成所有这些,我建议只需要点击并运行删除.也许使用批量日志恢复模型来最小化日志的影响.总的来说,我没有看到这个解决方案如何比以正确的顺序使用删除更快.
2014年,我在这里发表了一篇更详细的帖子:
Ed *_*all 34
使用内置的sp_msforeachtable存储过程.
要禁用所有约束:
EXEC sp_msforeachtable "ALTER TABLE ? NOCHECK CONSTRAINT ALL";
Run Code Online (Sandbox Code Playgroud)
要启用所有约束:
EXEC sp_msforeachtable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT ALL";
Run Code Online (Sandbox Code Playgroud)
删除所有表:
EXEC sp_msforeachtable "DROP TABLE ?";
Run Code Online (Sandbox Code Playgroud)
有一个简单的方法可以做到这一点。
\n-- Disable all the constraint in database\nEXEC sp_msforeachtable \'ALTER TABLE ? NOCHECK CONSTRAINT all\'\n\n-- Enable all the constraint in database\nEXEC sp_msforeachtable \'ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all\'\nRun Code Online (Sandbox Code Playgroud)\n参考SQL SERVER \xe2\x80\x93 禁用数据库中的所有外键约束 \xe2\x80\x93 启用数据库中的所有外键约束
\n一个很好的参考:http://msdn.microsoft.com/en-us/magazine/cc163442.aspx 在“禁用所有外键”部分下
受此启发,可以通过创建临时表并在该表中插入约束,然后删除约束,然后从该临时表重新应用它们来实现一种方法。说得够多了,这就是我要说的
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
89504 次 |
| 最近记录: |