2010-10-02 86 views
22

我有一个名为PX_Child的表,在PX_Parent上有一个外键。我想暂时禁用此FK约束,以便我可以截断PX_Parent。但我不确定这是怎么回事。禁用外键约束,仍不能截断表? (SQL Server 2005)

我已经试过这些命令

ALTER TABLE PX_Child NOCHECK CONSTRAINT ALL 

ALTER TABLE PX_Parent NOCHECK CONSTRAINT ALL 

(truncate commands) 

ALTER TABLE PX_Child CHECK CONSTRAINT ALL 

ALTER TABLE PX_Parent CHECK CONSTRAINT ALL 

但仍然截断告诉我它无法截断,因为一个外键约束的PX_Parent。我查看了所有网络,似乎无法找到我做错了什么,对于这个问题的基本性质感到抱歉。

+1

看起来像卡伦·德莱尼是为起关闭这个想法无意中负责。 [在这里她澄清](http://www.eggheadcafe.com/software/aspnet/29927698/cant-truncate-table.aspx)“您必须删除引用约束以截断表。” – 2010-10-02 00:37:32

回答

31

如果有任何外键引用它,包括禁用的约束,则不能截断表。您可能需要删除外键约束或使用DELETE命令。

+1

请参阅我的(5年后)以下答案,以了解如何快速生成“DROP CONSTRAINT”和“ADD CONSTRAINT”SQL – RJB 2016-04-24 00:53:22

5

即使禁用了约束,SQL Server也不会让您在约束存在时截断表。 删除约束并在截断表之后重新创建约束。 或者直接删除并重新创建这些表格,在您的应用程序中执行哪一个更容易。

+2

这是什么意思,它不是一个事务性命令?你可以把它回滚得很好。 'CREATE TABLE Blah(int); INSERT Blah VALUES(1); SELECT * FROM Blah; BEGIN TRAN; TRUNCATE TABLE Blah; SELECT * FROM Blah; ROLLBACK TRAN SELECT * FROM Blah; DROP TABLE Blah'。截断工作通过取消分配整个页面而不是删除行,但仍然是事务性的。 – ErikE 2010-10-02 01:11:07

+0

@Emtucifor:哎呀,好像我错误地解释了你是正确的文档!我删除了那条错误信息。 – 2010-10-02 01:47:14

+0

@Emtucifor,@pgroke,因为标准允许TRUNCATE是非事务性的,所以两者都是正确的,但允许实现将其交易。因此,按照定义的TRUNCATE并不保证可以进行回滚,但SqlServer(和Postgres)在标准之外添加了该承诺。 – 2010-10-02 10:43:14

10

有一个更容易的方法。我面临着同样的问题,发现这个解决方案: https://www.mssqltips.com/sqlservertip/3347/drop-and-recreate-all-foreign-key-constraints-in-sql-server/

如果你只是运行在你的数据库这个查询时,它会生成T-SQL你需要包括前/你的存储过程后,才能删除和然后恢复任何外键约束。

不要担心试图理解这个查询本身。

CREATE TABLE #x -- feel free to use a permanent table 
(
    drop_script NVARCHAR(MAX), 
    create_script NVARCHAR(MAX) 
); 

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

-- drop is easy, just build a simple concatenated list from sys.foreign_keys: 
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]; 

INSERT #x(drop_script) SELECT @drop; 

-- create is a little more complex. We need to generate the list of 
-- columns on both sides of the constraint, even though in most cases 
-- there is only one column. 
SELECT @create += N' 
ALTER TABLE ' 
    + QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name) 
    + ' ADD CONSTRAINT ' + QUOTENAME(fk.name) 
    + ' FOREIGN KEY (' + STUFF((SELECT ',' + QUOTENAME(c.name) 
    -- get all the columns in the constraint table 
    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) 
    -- get all the referenced columns 
    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.is_ms_shipped = 0 AND ct.is_ms_shipped = 0; 

UPDATE #x SET create_script = @create; 

PRINT @drop; 
PRINT @create; 

/* 
EXEC sp_executesql @drop 
-- clear out data etc. here 
EXEC sp_executesql @create; 
*/ 

生成一串:

ALTER TABLE [dbo].[Whatever] DROP CONSTRAINT.... 
-- 
ALTER TABLE [dbo].[Whatever] ADD CONSTRAINT.... 
+6

不好的建议:“不要担心试图理解这个查询本身”。不要在没有理解的情况下运行任何东西 – 2016-05-22 20:39:23

+0

是的,但它不是DB的生产版本 – RJB 2016-05-22 23:01:59

+2

理解查询如何工作并确保它不会造成任何伤害是有区别的。后者几乎总是更容易。 – wolfrevokcats 2016-07-09 09:15:33