我正在运行一个SSIS包,它将把几个表的数据从FlatFiles替换为数据库中的现有表。
我的包将截断表,然后插入新数据。当我运行我的SSIS包时,由于外键我得到一个例外。
我可以禁用约束,运行导入,然后重新启用它们吗?
答案 0 :(得分:78)
禁用外键约束:
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;
重新启用:
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;
但是,您将无法截断表,您必须按正确的顺序从中删除它们。如果您需要截断它们,则需要完全删除约束,然后重新创建它们。如果外键约束都是简单的单列约束,这很容易做到,但如果涉及多个列,则肯定会更复杂。
这是你可以尝试的东西。为了使其成为SSIS包的一部分,您需要在SSIS包运行时存储FK定义的位置(您将无法在一个脚本中完成所有操作)。所以在一些实用程序数据库中,创建一个表:
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('.', '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
现在,当您的SSIS包完成后,它应该调用另一个存储过程,其执行:
DECLARE @sql NVARCHAR(MAX);
SELECT @sql = cmd FROM other_database.dbo.PostCommand;
EXEC sp_executesql @sql;
如果你只是为了能够截断而不是删除而完成所有这些操作,我建议只需点击并运行删除即可。也许使用批量日志恢复模型来最小化日志的影响。总的来说,我没有看到这个解决方案如何比以正确的顺序使用删除更快。
2014年,我在这里发表了一篇更详细的文章:
答案 1 :(得分:30)
使用内置的 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 ?";
答案 2 :(得分:3)
在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
答案 3 :(得分:1)
禁用所有表约束
ALTER TABLE TableName NOCHECK CONSTRAINT ConstraintName
- 启用所有表约束
ALTER TABLE TableName CHECK CONSTRAINT ConstraintName
答案 4 :(得分:0)
不需要在sql上对sidable FK运行查询。如果您从表A到B有FK,您应该:
您还可以告诉目的地不要检查约束
答案 5 :(得分:0)
即使禁用外键,也无法截断表格。所以你可以使用 delete命令从表中删除所有记录,但要注意是否使用了删除 对于包含数百万条记录的表的命令,那么您的包将会很慢 并且您的事务日志大小将增加,它可能会占用宝贵的磁盘空间。
如果你放弃约束,你可能会用不洁净的数据填满你的桌子 当你尝试重新创建约束时,它可能不允许你,因为它会给出错误。 因此,请确保如果删除约束,则加载彼此正确相关的数据并满足要重新创建的约束关系。
所以请仔细考虑每种方法的优缺点,并根据您的要求使用
答案 6 :(得分:0)
如果您使用的数据库模式与“ .dbo”不同,或者您的数据库包含由多个字段组成的Pk,请不要使用卡特·梅德林的解决方案,否则会损坏您的数据库!!!
在使用不同的架构时,请尝试以下操作(不要忘记之前对数据库进行备份!):
// definition
function loadScript(scriptUrl) {
const script = document.createElement('script');
script.src = scriptUrl;
document.body.appendChild(script);
return new Promise(res => {
script.onLoad = function() {
res();
}
});
}
// use
loadScript('http:// .... /jquery.js')
.then(() => {
console.log('Script loaded!');
});
执行一些免Fk动作后,您可以使用
db, err := gorm.Open("postgres", "host='postgres'&user:docker&port=5432&dbname='docker'&password='password'&sslmode=disable")
答案 7 :(得分:0)
有一个简单的方法。
-- 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'
答案 8 :(得分:-2)
禁用所有索引(包括pk,它将禁用所有fks),然后重新启用pk。
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