Cannot truncate table because it is being referenced by a FOREIGN KEY constraint?
使用mssql2005,如果我首先截断子表(具有fk关系主键的表),是否可以截断具有外键约束的表?
我知道我也可以
- 使用不带WHERE子句的
DELETE ,然后使用RESEED 标识(或) - 删除FK,截断表,然后重新创建FK。
我以为只要我在父表之前截断了子表,我就可以不做上面的任何一个选项,但是我得到了这个错误:
Cannot truncate table 'TableName' because it is being referenced by a FOREIGN KEY constraint.
正确;不能截断具有FK约束的表。
通常我的流程是:
(当然,都是在一个交易中。)
当然,这只适用于子级已经被截断的情况。否则我会走另一条路,完全取决于我的数据的外观。(这里的变量太多了。)
最初的海报决定了为什么会出现这种情况;请参阅此答案了解更多详细信息。
1 2 | DELETE FROM TABLENAME DBCC CHECKIDENT ('DATABASENAME.dbo.TABLENAME',RESEED, 0) |
请注意,如果你有数百万以上的记录,这可能不是你想要的,因为这很慢。
由于
这就是为什么
不带
1 2 3 4 5 6 7 | -- Delete all records DELETE FROM [TableName] -- Set current ID to"1" -- If table already contains data, use"0" -- If table is empty and never insert data, use"1" -- Use SP https://github.com/reduardo7/TableTruncate DBCC CHECKIDENT ([TableName], RESEED, [0|1]) |
作为存储过程
https://github.com/reduardo7/tabletruncate
请注意,如果你有数百万以上的记录,这可能不是你想要的,因为这很慢。
上面提供的"丹佛市民"解决方案不适合我,但我喜欢它的精神,所以我修改了一些东西:
- 使其成为存储过程
- 更改了填充和重新创建外键的方式
- 原始脚本截断所有被引用的表,当被引用的表具有其他外键引用时,这可能会导致外键冲突错误。此脚本仅截断指定为参数的表。由用户决定,以正确的顺序对所有表多次调用此存储过程。
为了公众的利益,以下是更新后的脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | CREATE PROCEDURE [dbo].[truncate_non_empty_table] @TableToTruncate VARCHAR(64) AS BEGIN SET NOCOUNT ON -- GLOBAL VARIABLES DECLARE @i int DECLARE @Debug bit DECLARE @Recycle bit DECLARE @Verbose bit DECLARE @TableName varchar(80) DECLARE @ColumnName varchar(80) DECLARE @ReferencedTableName varchar(80) DECLARE @ReferencedColumnName varchar(80) DECLARE @ConstraintName varchar(250) DECLARE @CreateStatement varchar(max) DECLARE @DropStatement varchar(max) DECLARE @TruncateStatement varchar(max) DECLARE @CreateStatementTemp varchar(max) DECLARE @DropStatementTemp varchar(max) DECLARE @TruncateStatementTemp varchar(max) DECLARE @Statement varchar(max) -- 1 = Will not execute statements SET @Debug = 0 -- 0 = Will not create or truncate storage table -- 1 = Will create or truncate storage table SET @Recycle = 0 -- 1 = Will print a message on every step set @Verbose = 1 SET @i = 1 SET @CreateStatement = 'ALTER TABLE [dbo].[<tablename>] WITH NOCHECK ADD CONSTRAINT [<constraintname>] FOREIGN KEY([<column>]) REFERENCES [dbo].[<reftable>] ([<refcolumn>])' SET @DropStatement = 'ALTER TABLE [dbo].[<tablename>] DROP CONSTRAINT [<constraintname>]' SET @TruncateStatement = 'TRUNCATE TABLE [<tablename>]' -- Drop Temporary tables IF OBJECT_ID('tempdb..#FKs') IS NOT NULL DROP TABLE #FKs -- GET FKs SELECT ROW_NUMBER() OVER (ORDER BY OBJECT_NAME(parent_object_id), clm1.name) as ID, OBJECT_NAME(constraint_object_id) as ConstraintName, OBJECT_NAME(parent_object_id) as TableName, clm1.name as ColumnName, OBJECT_NAME(referenced_object_id) as ReferencedTableName, clm2.name as ReferencedColumnName INTO #FKs FROM sys.foreign_key_columns fk JOIN sys.columns clm1 ON fk.parent_column_id = clm1.column_id AND fk.parent_object_id = clm1.object_id JOIN sys.columns clm2 ON fk.referenced_column_id = clm2.column_id AND fk.referenced_object_id= clm2.object_id --WHERE OBJECT_NAME(parent_object_id) not in ('//tables that you do not wont to be truncated') WHERE OBJECT_NAME(referenced_object_id) = @TableToTruncate ORDER BY OBJECT_NAME(parent_object_id) -- Prepare Storage Table IF Not EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Internal_FK_Definition_Storage') BEGIN IF @Verbose = 1 PRINT '1. Creating Process Specific Tables...' -- CREATE STORAGE TABLE IF IT DOES NOT EXISTS CREATE TABLE [Internal_FK_Definition_Storage] ( ID int not null identity(1,1) primary key, FK_Name varchar(250) not null, FK_CreationStatement varchar(max) not null, FK_DestructionStatement varchar(max) not null, Table_TruncationStatement varchar(max) not null ) END ELSE BEGIN IF @Recycle = 0 BEGIN IF @Verbose = 1 PRINT '1. Truncating Process Specific Tables...' -- TRUNCATE TABLE IF IT ALREADY EXISTS TRUNCATE TABLE [Internal_FK_Definition_Storage] END ELSE PRINT '1. Process specific table will be recycled from previous execution...' END IF @Recycle = 0 BEGIN IF @Verbose = 1 PRINT '2. Backing up Foreign Key Definitions...' -- Fetch and persist FKs WHILE (@i <= (SELECT MAX(ID) FROM #FKs)) BEGIN SET @ConstraintName = (SELECT ConstraintName FROM #FKs WHERE ID = @i) SET @TableName = (SELECT TableName FROM #FKs WHERE ID = @i) SET @ColumnName = (SELECT ColumnName FROM #FKs WHERE ID = @i) SET @ReferencedTableName = (SELECT ReferencedTableName FROM #FKs WHERE ID = @i) SET @ReferencedColumnName = (SELECT ReferencedColumnName FROM #FKs WHERE ID = @i) SET @DropStatementTemp = REPLACE(REPLACE(@DropStatement,'<tablename>',@TableName),'<constraintname>',@ConstraintName) SET @CreateStatementTemp = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@CreateStatement,'<tablename>',@TableName),'<column>',@ColumnName),'<constraintname>',@ConstraintName),'<reftable>',@ReferencedTableName),'<refcolumn>',@ReferencedColumnName) SET @TruncateStatementTemp = REPLACE(@TruncateStatement,'<tablename>',@TableName) INSERT INTO [Internal_FK_Definition_Storage] SELECT @ConstraintName, @CreateStatementTemp, @DropStatementTemp, @TruncateStatementTemp SET @i = @i + 1 IF @Verbose = 1 PRINT ' > Backing up [' + @ConstraintName + '] from [' + @TableName + ']' END END ELSE PRINT '2. Backup up was recycled from previous execution...' IF @Verbose = 1 PRINT '3. Dropping Foreign Keys...' -- DROP FOREING KEYS SET @i = 1 WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage])) BEGIN SET @ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = @i) SET @Statement = (SELECT FK_DestructionStatement FROM [Internal_FK_Definition_Storage] WITH (NOLOCK) WHERE ID = @i) IF @Debug = 1 PRINT @Statement ELSE EXEC(@Statement) SET @i = @i + 1 IF @Verbose = 1 PRINT ' > Dropping [' + @ConstraintName + ']' END IF @Verbose = 1 PRINT '4. Truncating Tables...' -- TRUNCATE TABLES -- SzP: commented out as the tables to be truncated might also contain tables that has foreign keys -- to resolve this the stored procedure should be called recursively, but I dont have the time to do it... /* SET @i = 1 WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage])) BEGIN SET @Statement = (SELECT Table_TruncationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = @i) IF @Debug = 1 PRINT @Statement ELSE EXEC(@Statement) SET @i = @i + 1 IF @Verbose = 1 PRINT ' > ' + @Statement END */ IF @Verbose = 1 PRINT ' > TRUNCATE TABLE [' + @TableToTruncate + ']' IF @Debug = 1 PRINT 'TRUNCATE TABLE [' + @TableToTruncate + ']' ELSE EXEC('TRUNCATE TABLE [' + @TableToTruncate + ']') IF @Verbose = 1 PRINT '5. Re-creating Foreign Keys...' -- CREATE FOREING KEYS SET @i = 1 WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage])) BEGIN SET @ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = @i) SET @Statement = (SELECT FK_CreationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = @i) IF @Debug = 1 PRINT @Statement ELSE EXEC(@Statement) SET @i = @i + 1 IF @Verbose = 1 PRINT ' > Re-creating [' + @ConstraintName + ']' END IF @Verbose = 1 PRINT '6. Process Completed' END |
使用DELETE语句删除该表中的所有行后使用以下命令
1 2 3 | delete from tablename DBCC CHECKIDENT ('tablename', RESEED, 0) |
编辑:已更正的SQL Server语法
你可以按照这个步骤,通过
1 2 | delete from table_name dbcc checkident('table_name',reseed,0) |
如果出现错误,则必须重新设置主表。
这是我为使过程自动化而编写的一个脚本。希望能有所帮助。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | SET NOCOUNT ON -- GLOBAL VARIABLES DECLARE @i int DECLARE @Debug bit DECLARE @Recycle bit DECLARE @Verbose bit DECLARE @TableName varchar(80) DECLARE @ColumnName varchar(80) DECLARE @ReferencedTableName varchar(80) DECLARE @ReferencedColumnName varchar(80) DECLARE @ConstraintName varchar(250) DECLARE @CreateStatement varchar(max) DECLARE @DropStatement varchar(max) DECLARE @TruncateStatement varchar(max) DECLARE @CreateStatementTemp varchar(max) DECLARE @DropStatementTemp varchar(max) DECLARE @TruncateStatementTemp varchar(max) DECLARE @Statement varchar(max) -- 1 = Will not execute statements SET @Debug = 0 -- 0 = Will not create or truncate storage table -- 1 = Will create or truncate storage table SET @Recycle = 0 -- 1 = Will print a message on every step set @Verbose = 1 SET @i = 1 SET @CreateStatement = 'ALTER TABLE [dbo].[<tablename>] WITH NOCHECK ADD CONSTRAINT [<constraintname>] FOREIGN KEY([<column>]) REFERENCES [dbo].[<reftable>] ([<refcolumn>])' SET @DropStatement = 'ALTER TABLE [dbo].[<tablename>] DROP CONSTRAINT [<constraintname>]' SET @TruncateStatement = 'TRUNCATE TABLE [<tablename>]' -- Drop Temporary tables DROP TABLE #FKs -- GET FKs SELECT ROW_NUMBER() OVER (ORDER BY OBJECT_NAME(parent_object_id), clm1.name) as ID, OBJECT_NAME(constraint_object_id) as ConstraintName, OBJECT_NAME(parent_object_id) as TableName, clm1.name as ColumnName, OBJECT_NAME(referenced_object_id) as ReferencedTableName, clm2.name as ReferencedColumnName INTO #FKs FROM sys.foreign_key_columns fk JOIN sys.columns clm1 ON fk.parent_column_id = clm1.column_id AND fk.parent_object_id = clm1.object_id JOIN sys.columns clm2 ON fk.referenced_column_id = clm2.column_id AND fk.referenced_object_id= clm2.object_id WHERE OBJECT_NAME(parent_object_id) not in ('//tables that you do not wont to be truncated') ORDER BY OBJECT_NAME(parent_object_id) -- Prepare Storage Table IF Not EXISTS(SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Internal_FK_Definition_Storage') BEGIN IF @Verbose = 1 PRINT '1. Creating Process Specific Tables...' -- CREATE STORAGE TABLE IF IT DOES NOT EXISTS CREATE TABLE [Internal_FK_Definition_Storage] ( ID int not null identity(1,1) primary key, FK_Name varchar(250) not null, FK_CreationStatement varchar(max) not null, FK_DestructionStatement varchar(max) not null, Table_TruncationStatement varchar(max) not null ) END ELSE BEGIN IF @Recycle = 0 BEGIN IF @Verbose = 1 PRINT '1. Truncating Process Specific Tables...' -- TRUNCATE TABLE IF IT ALREADY EXISTS TRUNCATE TABLE [Internal_FK_Definition_Storage] END ELSE PRINT '1. Process specific table will be recycled from previous execution...' END IF @Recycle = 0 BEGIN IF @Verbose = 1 PRINT '2. Backing up Foreign Key Definitions...' -- Fetch and persist FKs WHILE (@i <= (SELECT MAX(ID) FROM #FKs)) BEGIN SET @ConstraintName = (SELECT ConstraintName FROM #FKs WHERE ID = @i) SET @TableName = (SELECT TableName FROM #FKs WHERE ID = @i) SET @ColumnName = (SELECT ColumnName FROM #FKs WHERE ID = @i) SET @ReferencedTableName = (SELECT ReferencedTableName FROM #FKs WHERE ID = @i) SET @ReferencedColumnName = (SELECT ReferencedColumnName FROM #FKs WHERE ID = @i) SET @DropStatementTemp = REPLACE(REPLACE(@DropStatement,'<tablename>',@TableName),'<constraintname>',@ConstraintName) SET @CreateStatementTemp = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@CreateStatement,'<tablename>',@TableName),'<column>',@ColumnName),'<constraintname>',@ConstraintName),'<reftable>',@ReferencedTableName),'<refcolumn>',@ReferencedColumnName) SET @TruncateStatementTemp = REPLACE(@TruncateStatement,'<tablename>',@TableName) INSERT INTO [Internal_FK_Definition_Storage] SELECT @ConstraintName, @CreateStatementTemp, @DropStatementTemp, @TruncateStatementTemp SET @i = @i + 1 IF @Verbose = 1 PRINT ' > Backing up [' + @ConstraintName + '] from [' + @TableName + ']' END END ELSE PRINT '2. Backup up was recycled from previous execution...' IF @Verbose = 1 PRINT '3. Dropping Foreign Keys...' -- DROP FOREING KEYS SET @i = 1 WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage])) BEGIN SET @ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = @i) SET @Statement = (SELECT FK_DestructionStatement FROM [Internal_FK_Definition_Storage] WITH (NOLOCK) WHERE ID = @i) IF @Debug = 1 PRINT @Statement ELSE EXEC(@Statement) SET @i = @i + 1 IF @Verbose = 1 PRINT ' > Dropping [' + @ConstraintName + ']' END IF @Verbose = 1 PRINT '4. Truncating Tables...' -- TRUNCATE TABLES SET @i = 1 WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage])) BEGIN SET @Statement = (SELECT Table_TruncationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = @i) IF @Debug = 1 PRINT @Statement ELSE EXEC(@Statement) SET @i = @i + 1 IF @Verbose = 1 PRINT ' > ' + @Statement END IF @Verbose = 1 PRINT '5. Re-creating Foreign Keys...' -- CREATE FOREING KEYS SET @i = 1 WHILE (@i <= (SELECT MAX(ID) FROM [Internal_FK_Definition_Storage])) BEGIN SET @ConstraintName = (SELECT FK_Name FROM [Internal_FK_Definition_Storage] WHERE ID = @i) SET @Statement = (SELECT FK_CreationStatement FROM [Internal_FK_Definition_Storage] WHERE ID = @i) IF @Debug = 1 PRINT @Statement ELSE EXEC(@Statement) SET @i = @i + 1 IF @Verbose = 1 PRINT ' > Re-creating [' + @ConstraintName + ']' END IF @Verbose = 1 PRINT '6. Process Completed' |
在网上其他地方找到的
1 2 3 4 5 | EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL' EXEC sp_MSForEachTable 'ALTER TABLE ? DISABLE TRIGGER ALL' -- EXEC sp_MSForEachTable 'DELETE FROM ?' -- Uncomment to execute EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL' EXEC sp_MSForEachTable 'ALTER TABLE ? ENABLE TRIGGER ALL' |
嗯,因为我没有找到我使用的非常简单的解决方案的例子,它是:
这就是:
1)从表
1 | ALTER TABLE TABLE_OWNING_CONSTRAINT DROP CONSTRAINT FK_PROBLEM_REASON |
3)截断所需表
1 | TRUNCATE TABLE TABLE_TO_TRUNCATE |
4)将键重新添加到第一个表中:
1 | ALTER TABLE TABLE_OWNING_CONSTRAINT ADD CONSTRAINT FK_PROBLEM_REASON FOREIGN KEY(ID) REFERENCES TABLE_TO_TRUNCATE (ID) |
就是这样。
如果我理解正确,您要做的是为涉及集成测试的DB建立一个干净的环境。
我这里的方法是删除整个模式,稍后再重新创建它。
原因:如果不删除约束,则不能截断表。残疾人也不行。你需要放下一切。我编写了一个脚本,删除所有约束,然后重新创建。
确保将其包装在事务中;)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | SET NOCOUNT ON GO 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 --DROP CONSTRAINT: DECLARE @dynSQL varchar(MAX); DECLARE cur CURSOR FOR SELECT ' ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] DROP CONSTRAINT ' + ForeignKeyConstraintName + ' ' FROM @table OPEN cur FETCH cur into @dynSQL WHILE @@FETCH_STATUS = 0 BEGIN exec(@dynSQL) print @dynSQL FETCH cur into @dynSQL END CLOSE cur DEALLOCATE cur --------------------- --HERE GOES YOUR TRUNCATES!!!!! --HERE GOES YOUR TRUNCATES!!!!! --HERE GOES YOUR TRUNCATES!!!!! truncate table your_table --HERE GOES YOUR TRUNCATES!!!!! --HERE GOES YOUR TRUNCATES!!!!! --HERE GOES YOUR TRUNCATES!!!!! --------------------- --ADD CONSTRAINT: DECLARE cur2 CURSOR FOR SELECT ' ALTER TABLE [' + ForeignKeyConstraintTableSchema + '].[' + ForeignKeyConstraintTableName + '] ADD CONSTRAINT ' + ForeignKeyConstraintName + ' FOREIGN KEY(' + ForeignKeyConstraintColumnName + ') REFERENCES [' + PrimaryKeyConstraintTableSchema + '].[' + PrimaryKeyConstraintTableName + '](' + PrimaryKeyConstraintColumnName + ') ' FROM @table OPEN cur2 FETCH cur2 into @dynSQL WHILE @@FETCH_STATUS = 0 BEGIN exec(@dynSQL) print @dynSQL FETCH cur2 into @dynSQL END CLOSE cur2 DEALLOCATE cur2 |
1 2 3 4 5 | SET FOREIGN_KEY_CHECKS = 0; truncate table"yourTableName"; SET FOREIGN_KEY_CHECKS = 1; |
截短对我不起作用,删除+重置是最好的方法。如果有一些人需要迭代大量的表来执行delete+resed,那么您可能会遇到一些没有标识列的表的问题,下面的代码会在尝试重设之前检查标识列是否存在。
1 2 3 4 5 | EXEC ('DELETE FROM [schemaName].[tableName]') IF EXISTS (Select * from sys.identity_columns where object_name(object_id) = 'tableName') BEGIN EXEC ('DBCC CHECKIDENT ([schemaName.tableName], RESEED, 0)') END |
我编写了以下方法并尝试对它们进行参数化,这样您就可以在
如果您的表中没有数百万条记录,那么这将很好地工作,并且没有任何alter命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 | --------------------------------------------------------------- ------------------- Just Fill Parameters Value ---------------- --------------------------------------------------------------- DECLARE @DbName AS NVARCHAR(30) = 'MyDb' --< Db Name DECLARE @Schema AS NVARCHAR(30) = 'dbo' --< Schema DECLARE @TableName AS NVARCHAR(30) = 'Book' --< Table Name ------------------ /Just Fill Parameters Value ---------------- DECLARE @Query AS NVARCHAR(500) = 'Delete FROM ' + @TableName EXECUTE sp_executesql @Query SET @Query=@DbName+'.'+@Schema+'.'+@TableName DBCC CHECKIDENT (@Query,RESEED, 0) |
- In above answer of mine the method of resolve the mentioned problem in the question is based on @s15199d answer.
B)截断
如果您的表有数百万条记录,或者代码中的alter命令没有任何问题,请使用以下命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | -- Book Student -- -- | BookId | Field1 | | StudentId | BookId | -- --------------------- ------------------------ -- | 1 | A | | 2 | 1 | -- | 2 | B | | 1 | 1 | -- | 3 | C | | 2 | 3 | --------------------------------------------------------------- ------------------- Just Fill Parameters Value ---------------- --------------------------------------------------------------- DECLARE @DbName AS NVARCHAR(30) = 'MyDb' DECLARE @Schema AS NVARCHAR(30) = 'dbo' DECLARE @TableName_ToTruncate AS NVARCHAR(30) = 'Book' DECLARE @TableName_OfOwnerOfConstraint AS NVARCHAR(30) = 'Student' --< Decelations About FK_Book_Constraint DECLARE @Ref_ColumnName_In_TableName_ToTruncate AS NVARCHAR(30) = 'BookId' --< Decelations About FK_Book_Constraint DECLARE @FK_ColumnName_In_TableOfOwnerOfConstraint AS NVARCHAR(30) = 'Fk_BookId' --< Decelations About FK_Book_Constraint DECLARE @FK_ConstraintName AS NVARCHAR(30) = 'FK_Book_Constraint' --< Decelations About FK_Book_Constraint ------------------ /Just Fill Parameters Value ---------------- DECLARE @Query AS NVARCHAR(2000) SET @Query= 'ALTER TABLE '+@TableName_OfOwnerOfConstraint+' DROP CONSTRAINT '+@FK_ConstraintName EXECUTE sp_executesql @Query SET @Query= 'Truncate Table '+ @TableName_ToTruncate EXECUTE sp_executesql @Query SET @Query= 'ALTER TABLE '+@TableName_OfOwnerOfConstraint+' ADD CONSTRAINT '+@FK_ConstraintName+' FOREIGN KEY('+@FK_ColumnName_In_TableOfOwnerOfConstraint+') REFERENCES '+@TableName_ToTruncate+'('+@Ref_ColumnName_In_TableName_ToTruncate+')' EXECUTE sp_executesql @Query |
In above answer of mine the method of resolve the mentioned problem in the question is based on @LauroWolffValenteSobrinho answer.
If you have more than one CONSTRAINT then you should append its codes like me to the above query
Also you can change the above code base @SerjSagan answer to disable an enable the constraint
这是我解决这个问题的办法。我用它来改变pk,但想法是一样的。希望这会有用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | PRINT 'Script starts' DECLARE @foreign_key_name varchar(255) DECLARE @keycnt int DECLARE @foreign_table varchar(255) DECLARE @foreign_column_1 varchar(255) DECLARE @foreign_column_2 varchar(255) DECLARE @primary_table varchar(255) DECLARE @primary_column_1 varchar(255) DECLARE @primary_column_2 varchar(255) DECLARE @TablN varchar(255) -->> Type the primary table name SET @TablN = '' --------------------------------------------------------------------------------------- ------------------------------ --Here will be created the temporary table with all reference FKs --------------------------------------------------------------------------------------------------------------------- PRINT 'Creating the temporary table' select cast(f.name as varchar(255)) as foreign_key_name , r.keycnt , cast(c.name as varchar(255)) as foreign_table , cast(fc.name as varchar(255)) as foreign_column_1 , cast(fc2.name as varchar(255)) as foreign_column_2 , cast(p.name as varchar(255)) as primary_table , cast(rc.name as varchar(255)) as primary_column_1 , cast(rc2.name as varchar(255)) as primary_column_2 into #ConTab from sysobjects f inner join sysobjects c on f.parent_obj = c.id inner join sysreferences r on f.id = r.constid inner join sysobjects p on r.rkeyid = p.id inner join syscolumns rc on r.rkeyid = rc.id and r.rkey1 = rc.colid inner join syscolumns fc on r.fkeyid = fc.id and r.fkey1 = fc.colid left join syscolumns rc2 on r.rkeyid = rc2.id and r.rkey2 = rc.colid left join syscolumns fc2 on r.fkeyid = fc2.id and r.fkey2 = fc.colid where f.type = 'F' and p.name = @TablN ORDER BY cast(p.name as varchar(255)) --------------------------------------------------------------------------------------------------------------------- --Cursor, below, will drop all reference FKs --------------------------------------------------------------------------------------------------------------------- DECLARE @CURSOR CURSOR /*Fill in cursor*/ PRINT 'Cursor 1 starting. All refernce FK will be droped' SET @CURSOR = CURSOR SCROLL FOR select foreign_key_name , keycnt , foreign_table , foreign_column_1 , foreign_column_2 , primary_table , primary_column_1 , primary_column_2 from #ConTab OPEN @CURSOR FETCH NEXT FROM @CURSOR INTO @foreign_key_name, @keycnt, @foreign_table, @foreign_column_1, @foreign_column_2, @primary_table, @primary_column_1, @primary_column_2 WHILE @@FETCH_STATUS = 0 BEGIN EXEC ('ALTER TABLE ['+@foreign_table+'] DROP CONSTRAINT ['+@foreign_key_name+']') FETCH NEXT FROM @CURSOR INTO @foreign_key_name, @keycnt, @foreign_table, @foreign_column_1, @foreign_column_2, @primary_table, @primary_column_1, @primary_column_2 END CLOSE @CURSOR PRINT 'Cursor 1 finished work' --------------------------------------------------------------------------------------------------------------------- --Here you should provide the chainging script for the primary table --------------------------------------------------------------------------------------------------------------------- PRINT 'Altering primary table begin' TRUNCATE TABLE table_name PRINT 'Altering finished' --------------------------------------------------------------------------------------------------------------------- --Cursor, below, will add again all reference FKs -------------------------------------------------------------------------------------------------------------------- PRINT 'Cursor 2 starting. All refernce FK will added' SET @CURSOR = CURSOR SCROLL FOR select foreign_key_name , keycnt , foreign_table , foreign_column_1 , foreign_column_2 , primary_table , primary_column_1 , primary_column_2 from #ConTab OPEN @CURSOR FETCH NEXT FROM @CURSOR INTO @foreign_key_name, @keycnt, @foreign_table, @foreign_column_1, @foreign_column_2, @primary_table, @primary_column_1, @primary_column_2 WHILE @@FETCH_STATUS = 0 BEGIN EXEC ('ALTER TABLE [' +@foreign_table+ '] WITH NOCHECK ADD CONSTRAINT [' +@foreign_key_name+ '] FOREIGN KEY(['+@foreign_column_1+']) REFERENCES [' +@primary_table+'] (['+@primary_column_1+'])') EXEC ('ALTER TABLE [' +@foreign_table+ '] CHECK CONSTRAINT [' +@foreign_key_name+']') FETCH NEXT FROM @CURSOR INTO @foreign_key_name, @keycnt, @foreign_table, @foreign_column_1, @foreign_column_2, @primary_table, @primary_column_1, @primary_column_2 END CLOSE @CURSOR PRINT 'Cursor 2 finished work' --------------------------------------------------------------------------------------------------------------------- PRINT 'Temporary table droping' drop table #ConTab PRINT 'Finish' |
以下内容即使在fk约束下也适用于我,并将以下答案组合在一起,只删除指定的表:
- 事务自动回滚
- 通过逗号分隔的列表循环
- 执行动态SQL(使用变量中的表名)
- 删除并重新设置表(在此线程中)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | USE [YourDB]; DECLARE @TransactionName varchar(20) = 'stopdropandroll'; BEGIN TRAN @TransactionName; set xact_abort on; /* automatic rollback https://stackoverflow.com/a/1749788/1037948 */ -- ===== DO WORK // ===== -- dynamic sql placeholder DECLARE @SQL varchar(300); -- LOOP: https://stackoverflow.com/a/10031803/1037948 -- list of things to loop DECLARE @delim char = ';'; DECLARE @foreach varchar(MAX) = 'Table;Names;Separated;By;Delimiter' + @delim + 'AnotherName' + @delim + 'Still Another'; DECLARE @token varchar(MAX); WHILE len(@foreach) > 0 BEGIN -- set current loop token SET @token = left(@foreach, charindex(@delim, @foreach+@delim)-1) -- ======= DO WORK // =========== -- dynamic sql (parentheses are required): https://stackoverflow.com/a/989111/1037948 SET @SQL = 'DELETE FROM [' + @token + ']; DBCC CHECKIDENT (''' + @token + ''',RESEED, 0);'; -- https://stackoverflow.com/a/11784890 PRINT @SQL; EXEC (@SQL); -- ======= // END WORK =========== -- continue loop, chopping off token SET @foreach = stuff(@foreach, 1, charindex(@delim, @foreach+@delim), '') END -- ===== // END WORK ===== -- review and commit SELECT @@TRANCOUNT as TransactionsPerformed, @@ROWCOUNT as LastRowsChanged; COMMIT TRAN @TransactionName; |
注:
我认为按您希望删除的顺序(即先删除依赖项)声明表仍然有帮助。正如在这个答案中看到的,您可以用替换所有表而不是循环特定的名称
1 | EXEC sp_MSForEachTable 'DELETE FROM ?; DBCC CHECKIDENT (''?'',RESEED, 0);'; |
对于
1 2 3 4 5 6 7 8 9 10 | ALTER TABLE Orders NOCHECK CONSTRAINT [FK_dbo.Orders_dbo.Customers_Customer_Id] GO TRUNCATE TABLE Customers GO ALTER TABLE Orders WITH CHECK CHECK CONSTRAINT [FK_dbo.Orders_dbo.Customers_Customer_Id] GO |
@丹佛市民的回答对我来说不太管用,但我修改了它来解释:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | DECLARE @Debug bit = 0; -- List of tables to truncate select SchemaName, Name into #tables from (values ('schema', 'table') ,('schema2', 'table2') ) as X(SchemaName, Name) BEGIN TRANSACTION TruncateTrans; with foreignKeys AS ( SELECT SCHEMA_NAME(fk.schema_id) as SchemaName ,fk.Name as ConstraintName ,OBJECT_NAME(fk.parent_object_id) as TableName ,OBJECT_NAME(fk.referenced_object_id) as ReferencedTableName ,fc.constraint_column_id ,COL_NAME(fk.parent_object_id, fc.parent_column_id) AS ColumnName ,COL_NAME(fk.referenced_object_id, fc.referenced_column_id) as ReferencedColumnName ,fk.delete_referential_action_desc ,fk.update_referential_action_desc FROM sys.foreign_keys AS fk JOIN sys.foreign_key_columns AS fc ON fk.object_id = fc.constraint_object_id JOIN #tables tbl ON SCHEMA_NAME(fk.schema_id) = tbl.SchemaName AND OBJECT_NAME(fc.referenced_object_id) = tbl.Name ) select quotename(fk.ConstraintName) AS ConstraintName ,quotename(fk.SchemaName) + '.' + quotename(fk.TableName) AS TableName ,quotename(fk.SchemaName) + '.' + quotename(fk.ReferencedTableName) AS ReferencedTableName ,replace(fk.delete_referential_action_desc, '_', ' ') AS DeleteAction ,replace(fk.update_referential_action_desc, '_', ' ') AS UpdateAction ,STUFF(( SELECT ',' + quotename(fk2.ColumnName) FROM foreignKeys fk2 WHERE fk2.ConstraintName = fk.ConstraintName ORDER BY fk2.constraint_column_id FOR XML PATH(''),TYPE ).value('.','VARCHAR(MAX)'),1,1,'') AS ColumnNames ,STUFF(( SELECT ',' + quotename(fk2.ReferencedColumnName) FROM foreignKeys fk2 WHERE fk2.ConstraintName = fk.ConstraintName ORDER BY fk2.constraint_column_id FOR XML PATH(''),TYPE ).value('.','VARCHAR(MAX)'),1,1,'') AS ReferencedColumnNames into #FKs from foreignKeys fk GROUP BY fk.SchemaName, fk.ConstraintName, fk.TableName, fk.ReferencedTableName, fk.delete_referential_action_desc, fk.update_referential_action_desc -- Drop FKs select identity(int,1,1) as ID, 'ALTER TABLE ' + fk.TableName + ' DROP CONSTRAINT ' + fk.ConstraintName AS script into #scripts from #FKs fk -- Truncate insert into #scripts select distinct 'TRUNCATE TABLE ' + fk.TableName AS script from #FKs fk -- Recreate insert into #scripts select 'ALTER TABLE ' + fk.TableName + ' WITH CHECK ADD CONSTRAINT ' + fk.ConstraintName + ' FOREIGN KEY ('+ fk.ColumnNames +')' + ' REFERENCES ' + fk.ReferencedTableName +' ('+ fk.ReferencedColumnNames +')' + ' ON DELETE ' + fk.DeleteAction + ' ON UPDATE ' + fk.UpdateAction AS script from #FKs fk DECLARE @script nvarchar(MAX); DECLARE curScripts CURSOR FOR select script from #scripts order by ID OPEN curScripts WHILE 1=1 BEGIN FETCH NEXT FROM curScripts INTO @script IF @@FETCH_STATUS != 0 BREAK; print @script; IF @Debug = 0 EXEC (@script); END CLOSE curScripts DEALLOCATE curScripts drop table #scripts drop table #FKs drop table #tables COMMIT TRANSACTION TruncateTrans; |
如果在我的案例中这些答案都不起作用,那么就这样做:
祝你好运!
在SSMS中,我打开了显示键的图表。在删除了键并截断了文件之后,我刷新了该文件,然后将重点放在图表上,并通过清除然后还原标识框创建了一个更新。保存图表会弹出一个"保存"对话框,而不是"在工作时在数据库中进行了更改"对话框,单击"是"会还原该键,并从图表中的锁定副本还原该键。
如果你在任何频率下这样做,甚至是在时间表上,我绝对,明确地永远不会使用DML声明。写入事务日志的成本太高了,将整个数据库设置为
不幸的是,最好的办法是艰苦卓绝。即:
- 删除约束
- 截断表
- 重新创建约束
我执行此操作的过程包括以下步骤:
这种性质的脚本应该在
我刚刚发现,只要先禁用子表上的约束,就可以在具有子表外键约束的父表上使用truncate table。例如。
外键约束子表上的子表,引用父表
1 2 3 4 | ALTER TABLE CHILD_TABLE DISABLE CONSTRAINT child_par_ref; TRUNCATE TABLE CHILD_TABLE; TRUNCATE TABLE PARENT_TABLE; ALTER TABLE CHILD_TABLE ENABLE CONSTRAINT child_par_ref; |
最简单的方法:1-输入phpmyadmin2-单击左栏中的表名3-点击操作(顶部菜单)4-点击"清空表格(截断)5-禁用"启用外键检查"框6 -完成!
链接到图像教程教程:http://www.imageno.com/wz6gv1wuqajrpic.html(对不起,我没有足够的信誉来上传图片:p)
你可以试试
服务器将向您显示限制和表的名称,并删除该表,您可以删除所需的内容。
1 2 3 4 | SET FOREIGN_KEY_CHECKS=0; TRUNCATE table1; TRUNCATE table2; SET FOREIGN_KEY_CHECKS=1; |
引用-截断外键约束表
在MySQL中为我工作