Truncate Table With Foreign Key - sql-server

I have one database having above 1000+ tables. I am creating fresh Blank setup. For that i have to truncate all the tables but some of the tables i do not wish to truncate so i created on table and stored the names in the table.
----------- Create hardcode table ----------------------
Create table TblHardCodeTableNotToTruncate(TableName varchar(100))
go
insert into TblHardCodeTableNotToTruncate
select 'TblHardCodeTableNotToTruncate'
go
---- insert the table names which dont wish to truncate ------------
Insert into TblHardCodeTableNotToTruncate
select 'TblAccount'
go
Insert into TblHardCodeTableNotToTruncate
select 'TblCity'
go
etc, Following is the query i used to truncate all the tables except these inserted tables
------------------------- Truncate all the tables except the tables specified in the Hardcode table -------------------------
EXEC sp_MSForEachTable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL'
GO
EXEC sp_MSForEachTable 'ALTER TABLE ? DISABLE TRIGGER ALL'
GO
DECLARE #TBLTEMP TABLE(TABLENAME VARCHAR(100))
insert into #TBLTEMP
select name from sysobjects where xtype = 'U'
delete from #TBLTEMP where tablename in (
select tablename from TblHardCodeTableNotToTruncate)
DECLARE #SQLQUERY VARCHAR(MAX) =''
DECLARE #INTCNT INT = 1
DECLARE #TABLENAME VARCHAR(100) =''
WHILE (SELECT COUNT(*) FROM #TBLTEMP) > 0
BEGIN
select top 1 #TABLENAME = TABLENAME from #TBLTEMP
SET #SQLQUERY = 'Truncate table ' + #TABLENAME
EXEC(#SQLQUERY)
PRINT #SQLQUERY
DELETE FROM #TBLTEMP WHERE TABLENAME = #TABLENAME
END
go
EXEC sp_MSForEachTable 'ALTER TABLE ? CHECK CONSTRAINT ALL'
GO
EXEC sp_MSForEachTable 'ALTER TABLE ? ENABLE TRIGGER ALL'
go
But i get the error foreign key reference error. I know i need to drop constraint before doing it. But is there any way to do it as i cannot drop then truncate and again add each time with so many tables. Is there any unique script can we write in below which will drop constraint if exists,truncate table and add the dropped constraint again to the table again.

I'm afraid that there is no way to do that without dropping constraints,
you can write a code that extracts the constraints for the tables and drop them it's simple.
Create a temporary table and use this code to get the tables constraint and notice that the sysconstraints.status must be 1 or 3 to get foreign and primary keys:
Select SysObjects.[Name] As "Constraint Name",
Tabls.[Name] as "Table Name",
Cols.[Name] As "Column Name"
From SysObjects Inner Join
(Select [Name],[ID] From SysObjects) As Tabls
On Tabls.[ID] = Sysobjects.[Parent_Obj]
Inner Join sysconstraints On sysconstraints.Constid = Sysobjects.[ID]
Inner Join SysColumns Cols On Cols.[ColID] = sysconstraints.[ColID]
And Cols.[ID] = Tabls.[ID]
where sysconstraints.status in (1, 3)
order by [Tabls].[Name]
you gonna have to recreate these constraints again after truncate, that's simple too, but I'm not gonna do all your job :)

Even if all tabled are empty and you disable all constraints the truncate ill fail due to the mere FK existence. You really must drop it.
You can create a script to automate it (truncate all tables dropping and recreating FKs)
I found one here (use with discretion)
http://www.sqlservercentral.com/scripts/Development/62892/
Also if you just want to create a "blanket" DB you can export the script to create all objects and just populate that few (domain?) tables do you need.

Related

How to DROP table in correct order in SQL SERVER 2014?

I have following 5 tables and 1 table is connected as Foreign key in 2 tables. My dilemma is that I cannot figure out which table to drop first. below is the drop table code I am trying and I have created tables in following order
Updated Drop Table Code:
IF EXISTS (SELECT*FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='[Student Major]')
BEGIN
DROP TABLE [Student Major]
END
GO
IF EXISTS (SELECT*FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Major')
BEGIN
DROP TABLE Major
END
GO
IF EXISTS (SELECT*FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Citizenship')
BEGIN
DROP TABLE Citizenship
END
GO
IF EXISTS (SELECT*FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Country')
BEGIN
DROP TABLE Country
END
IF EXISTS (SELECT*FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='Student')
BEGIN
DROP TABLE Student
END
GO
CREATE TABLE Student(
[Student ID] INT IDENTITY PRIMARY KEY
,[First Name] varchar (50) NOT NULL
,[Last Name] varchar (30) NOT NULL
)
GO
CREATE TABLE Country(
[Country ID] int identity PRIMARY KEY NOT NULL
,[Country of Birth] varchar (10)
,[Student ID] int FOREIGN KEY REFERENCES Student([Student ID]) NOT NULL
)
GO
CREATE TABLE Citizenship(
[Citizenship ID] int identity PRIMARY KEY
,[Country of Citizenship1] varchar (10)
,[Country of Citizenship2] varchar (10)
,[Student ID] int FOREIGN KEY REFERENCES Student([Student ID]) NOT NULL
,[Country ID] int FOREIGN KEY REFERENCES Country([Country ID]) NOT NULL
)
GO
CREATE TABLE Major(
[Major ID] int identity PRIMARY KEY
,[Major Name] varchar(30) NOT NULL
)
GO
CREATE TABLE [Student Major](
[Student MajorID] int identity
,[Student ID] int FOREIGN KEY REFERENCES Student([Student ID])
,[Major ID] int FOREIGN KEY REFERENCES Major([Major ID])
,[Graduated Major] varchar (30) NOT NULL
)
GO
I Would like to drop table in correct order
Errors:
Could not drop object 'Student' because it is referenced by a FOREIGN KEY constraint.
Also,Please provide explanation of dropping the table. I am new to SQL.
Thanks in advance!
Here is the way that I usually do it:
SELECT 'ALTER TABLE [' + O.[name] + '] DROP ' + F.[name]
FROM sys.objects O
INNER JOIN sys.foreign_keys F ON (F.parent_object_id = O.object_id)
WHERE O.[type] = 'U'
SELECT 'DROP TABLE [' + [name] + ']'
FROM sys.objects
WHERE [type] = 'U'
ORDER BY create_date DESC
This will generate a record set such as
ALTER TABLE Foo DROP FK_BLAH
ALTER TABLE Bar DROP FK_BAH
...
DROP TABLE Foo
DROP TABLE Bar
Which, you can then just copy and paste into a query window, and run from there.
(At the time that I'm writing this answer, I don't have access to an instance of SQL server, but I use code like the above all the time.)
DROP TABLE Student_Major; GO
SELECT 1 FROM Citizenship; GO
DROP TABLE Citizenship; GO
SELECT 1 FROM Major; GO
DROP TABLE Major; GO
SELECT 1 FROM Country; GO
DROP TABLE Country; GO
SELECT 1 FROM Student; GO
DROP TABLE Student; GO
It's just like you said, it has to be in the order so that any table that is referenced by a FK is not dropped, as long as the FK is there.
EDIT: GO forces the end of the batch
EDIT: I notice you have the GO in there already. You could use Information_schema to find the constraints associated with the table and drop them first, but I feel like you shouldn't need to do that. What if you injected a dummy query imbetween each DROP statement. It's hacky but if you don't feel like having to understand all the information_schema stuff it might be easier if it works.
You could first remove all FK constraints by:
ALTER TABLE ... DROP CONSTRAINT ...;
Then drop tables in any order.
If you are using SQL Server 2016 and above you could use DIE(drop if exists) and multiple tables at-once (still order matters):
DROP TABLE IF EXISTS [Student Major], Major, Citizenship, Country,Student;
DBFiddle Demo
If you are in doubt, and don't want to remove your constraints for some reason, you can always drop your tables in the exact opposite order in which you created them.
Since the first table doesn't reference any other, but maybe is referenced by other tables created after it, you should delete it last.
For the remaining tables, apply same logic. The first of the remaining tables is to be deleted last among them, and so on.

How can I delete or alter a default constraint from table in SQL Server database for multiple database?

I have gone thorough these previous questions Q1, Q2, Q3. Using this I can catch my exact constraint name. But it is not enough for me.
For example I have done somthing
ALTER TABLE dbo.Documents ADD ShowOnHandset BIT NOT NULL DEFAULT 'FALSE'
Here automatically my constrant named by the machine was DF__Documents__ShowO__7AB2122C on my machine. But I have run the same script in multiple PC, on those PC those constraint are almost same except the last hashed value. DF__Documents__ShowO__54A20B0D DF__Documents__ShowO__5D5216D7
I have seen that the last 8 bit hashed value is not similar. But I need to remove this constraint from all table and I want to replace them with
ALTER TABLE dbo.Documents ADD ShowOnHandset BIT NOT NULL DEFAULT ((1))
But I can't identify the the exact constraint name, so how can I drop it using a single script?
I have found hard-coded solution by those mentioned questions. But I need a single script to do it. Please help me to solve this.
I can catch the constraint name using this code
select name from sys.objects where name like 'DF__Documents__ShowO%'
I know the way how to delete it. Here it is.
ALTER TABLE dbo.AppSystems DROP constraint [constraint_name]
But I am unable to do it. Because I couldn't put the value constraint_name even if I can caught it. So how could I put this name here to drop it.
Update Modified the Question.
Run this and output as text, then copy the result and run in another query window
Fritz with the code below to ADD the updated constraint:
;With cte As (select object_id From sys.objects where name like 'DF__Documents__ShowO%')
Select 'Alter Table ' + Object_Name(df.object_id) + N' Add Constraint Default (1) For ShowOnHandset'
From sys.default_constraints As df
Join cte As c
On c.object_id = df.object_id
This deletes the constraints
;With cte As (select object_id From sys.objects where name like 'DF__Documents__ShowO%')
Select 'Alter Table ' + Object_Name(df.object_id) + N' Drop Constraint [' + df.Name + ']'
From sys.default_constraints As df
Join cte As c
On c.object_id = df.object_id
In MS SQL you can specify constraint name explicit:
ALTER TABLE dbo.Documents ADD ShowOnHandset BIT NOT NULL CONSTRAINT DF_Documents_ShowOnHandset DEFAULT 'FALSE'
Try dynamic query:
Declare #MyVariable varchar(max)
Declare #Variable varchar(max)
Set #MyVariable=(Select name from sys.objects
where parent_object_id=Object_ID('Documents','U') and name like 'DF__Documents__Show%')
Set #variable='ALTER TABLE dbo.AppSystems DROP constraint' +#MyVariable
Exec(#variable)

How can I alter a smalldatetime column with a default to be datetime?

I have a number of columns in my database that were originally created as smalldatetime and that really need to be datetime. Many of these columns were created with the DDL:
[columnname] smalldatetime not null default getdate()
...which means that in order to alter the column's type, I first have to drop the default, and then re-create the default after altering it.
Of course, I didn't specify a name for the default in the DDL, so the columns all have defaults with names like DF__CaseLock__CaseCo__182C9B23. And when my application creates its database, it does so by executing a script, so the names of the defaults in my customers' databases are (I'm guessing; I haven't verified this) different from their names in mine.
And even if I know the name of the default constraint, I can't figure out the syntax for adding it back in after I drop it. In fact, it's not clear to me that it's possible to add a default constraint to an existing column.
It appears that what I have to do is something like this:
declare #t table (id int not null primary key, date smalldatetime null)
insert into #t (id, date)
select id, date_column from my_table
drop constraint constraint_name
alter table my_table drop column date_column;
alter table my_table add date_column datetime default getdate()
update my_table set date_column = t.date FROM my_table m JOIN #t t ON m.id = t.ID
...only I can only write that script if I know what constraint_name is, because I can't drop a column that's referenced in a constraint.
Is this really that hard?
You can add a default constraint like this:
ALTER TABLE TableName
ADD CONSTRAINT DF_DefaultName DEFAULT 'Default Value' FOR ColumnName
You can interrogate the sys tables to find the existing constraints. When you add them back in, you should provide an explicit name for them. Here's a blog post that has a number of scripts for dealing with dropping/adding unnamed constraints. Hope that helps!
I'm afraid you have to resort to dynamic SQL.
Bear in mind though that any data that was previously set by the old default will remain.
DECLARE #query varchar(256)
SET #query = (
SELECT 'ALTER TABLE my_table DROP CONSTRAINT ' + d.name
FROM sysobjects d
INNER JOIN sysobjects t ON t.id = d.parent_obj
WHERE d.type = 'D'
AND t.name = 'my_table')
EXEC(#query)
ALTER TABLE my_table
ADD CONSTRAINT DF_date_column default getdate() for date_column
EDIT: Where multiple default columns exist in my_table:
CREATE TABLE #Defaults (
strName varchar(256) PRIMARY KEY
)
INSERT INTO #Defaults (strName)
SELECT d.name
FROM sysobjects d
INNER JOIN sysobjects t ON t.id = d.parent_obj
WHERE d.type = 'D'
AND t.name = 'my_table'
DECLARE #name varchar(256), #query varchar(256)
SET #name = (SELECT TOP 1 strName FROM #Defaults)
WHILE #name IS NOT NULL
BEGIN
SET #query = 'ALTER TABLE my_table DROP CONSTRAINT ' + #name
EXEC(#query)
DELETE FROM #Defaults
WHERE strName = #name
SET #name = (SELECT TOP 1 strName FROM #Defaults)
END
ALTER TABLE my_table
ADD CONSTRAINT DF_date_column1 default getdate() for date_column1
ALTER TABLE my_table
ADD CONSTRAINT DF_date_column2 default getdate() for date_column2
DROP TABLE #Defaults

Drop foreign key without knowing the name of the constraint?

I have created one table using the below command:
create table Table1(
Id int Not Null
Foreign key
references Table2(Id)
on delete cascade
on update cascade,
UserName nvarchar(150),
TimeInSeconds int Not Null
primary key(Id,TimeInSeconds)
);
But now I want to drop the foreign key.
As I haven't given a constraint name, I can't use:
Alter table <tablename>
drop foreign key <foreign key name>
Is there any way?
You can find the name of the constraint in INFORMATION_SCHEMA.TABLE_CONSTRAINTS
select CONSTRAINT_NAME
from INFORMATION_SCHEMA.TABLE_CONSTRAINTS
where TABLE_NAME = 'Table1'
Similar to Ed's Answer but you can use this to select the key name based on the table and column name.
That way you can run it in a script or maybe as a subquery to drop the constraint.
SELECT CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_NAME = 'post'
AND COLUMN_NAME = 'userID'
Expanding on the answers since I ran into some gotchas. Also, I had 2 foreign keys declared, so I added an optional key to keep, if it's null it'll just be ignored:
declare #name varchar(255),
#table varchar(255) = 'mytable',
#column varchar(255) = 'mykeycolumn',
#validkey varchar(255) = 'mykeyIwanttokeep'
SELECT #name = CONSTRAINT_NAME
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE TABLE_NAME = #table
AND COLUMN_NAME = #column
AND (CONSTRAINT_NAME != #validkey or #validkey is null)
declare #sql varchar(1023) = 'alter table ' + #table + ' drop ' + #name
exec (#sql)
A SQL Server option:
DECLARE #foreignkey varchar(100)
DECLARE #tablename varchar(100)
DECLARE #command nvarchar(1000)
DECLARE db_cursor CURSOR FOR
SELECT fk.name, t.name
FROM sys.foreign_keys fk
JOIN sys.tables t ON t.object_id = fk.parent_object_id
WHERE t.name IN (
'table_1_name_here',
'table_2_name_here'
)
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #foreignkey, #tablename
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #command = 'ALTER TABLE ' + #tablename + ' DROP CONSTRAINT ' + #foreignkey
EXECUTE(#command)
FETCH NEXT FROM db_cursor INTO #foreignkey, #tablename
END
CLOSE db_cursor
DEALLOCATE db_cursor
The SQL selects all the constraints for the tables you care about into a cursor and drops them one by one. All you need to know are the names of the tables you want them dropped from.
To drop a foreign key use the following commands :
SHOW CREATE TABLE table_name;
ALTER TABLE table_name DROP FOREIGN KEY table_name_ibfk_3;
("table_name_ibfk_3" is constraint foreign key name assigned for unnamed constraints). It varies.
ALTER TABLE table_name DROP column_name.
If you just look at the table in enterprise manager / management studio you will be able to see the list of keys and delete it from there.
Never mind, below is Postgres syntax. It would be better if the question had sql server in the title as I didn't notice the tag
You could also drop and re-add the primary key on the parent table using cascade. This will remove any foreign keys that reference that table without you needing to know the foreign key names.
ALTER TABLE parent_table
DROP CONSTRAINT 'pk_id' CASCADE
-- add back pk
ALTER TABLE parent_table
ADD CONSTRAINT 'pk_id' PRIMARY KEY (id)
WARNING: you'd want to check all the dependencies first and if there are other tables, you'd need to add back their foreign keys. That does allow you to name the foreign keys properly when you add them back. This approach also may not be viable in a high transaction system due to the blocking transaction.
you can put:
> show create table tablename;
you will see how was created the table...columns, types...etc. and you could see your constraint name.

How do you truncate all tables in a database using TSQL?

I have a test environment for a database that I want to reload with new data at the start of a testing cycle. I am not interested in rebuilding the entire database- just simply "re-setting" the data.
What is the best way to remove all the data from all the tables using TSQL? Are there system stored procedures, views, etc. that can be used? I do not want to manually create and maintain truncate table statements for each table- I would prefer it to be dynamic.
When dealing with deleting data from tables which have foreign key relationships - which is basically the case with any properly designed database - we can disable all the constraints, delete all the data and then re-enable constraints
-- disable all constraints
EXEC sp_MSForEachTable "ALTER TABLE ? NOCHECK CONSTRAINT all"
-- delete data in all tables
EXEC sp_MSForEachTable "DELETE FROM ?"
-- enable all constraints
exec sp_MSForEachTable "ALTER TABLE ? WITH CHECK CHECK CONSTRAINT all"
More on disabling constraints and triggers here
if some of the tables have identity columns we may want to reseed them
EXEC sp_MSForEachTable "DBCC CHECKIDENT ( '?', RESEED, 0)"
Note that the behaviour of RESEED differs between brand new table, and one which had had some data inserted previously from BOL:
DBCC CHECKIDENT ('table_name', RESEED, newReseedValue)
The current identity value is set to
the newReseedValue. If no rows have
been inserted to the table since it
was created, the first row inserted
after executing DBCC CHECKIDENT will
use newReseedValue as the identity.
Otherwise, the next row inserted will
use newReseedValue + 1. If the value
of newReseedValue is less than the
maximum value in the identity column,
error message 2627 will be generated
on subsequent references to the table.
Thanks to Robert for pointing out the fact that disabling constraints does not allow to use truncate, the constraints would have to be dropped, and then recreated
For SQL 2005,
EXEC sp_MSForEachTable 'TRUNCATE TABLE ?'
Couple more links for 2000 and 2005/2008..
Here's the king daddy of database wiping scripts. It will clear all tables and reseed them correctly:
SET QUOTED_IDENTIFIER ON;
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? NOCHECK CONSTRAINT ALL'
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? DISABLE TRIGGER ALL'
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; DELETE FROM ?'
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? CHECK CONSTRAINT ALL'
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON; ALTER TABLE ? ENABLE TRIGGER ALL'
EXEC sp_MSforeachtable 'SET QUOTED_IDENTIFIER ON';
IF NOT EXISTS (
SELECT
*
FROM
SYS.IDENTITY_COLUMNS
JOIN SYS.TABLES ON SYS.IDENTITY_COLUMNS.Object_ID = SYS.TABLES.Object_ID
WHERE
SYS.TABLES.Object_ID = OBJECT_ID('?') AND SYS.IDENTITY_COLUMNS.Last_Value IS NULL
)
AND OBJECTPROPERTY( OBJECT_ID('?'), 'TableHasIdentity' ) = 1
DBCC CHECKIDENT ('?', RESEED, 0) WITH NO_INFOMSGS;
Enjoy, but be careful!
The simplest way of doing this is to
open up SQL Management Studio
navigate to your database
Right-click and select Tasks->Generate Scripts (pic 1)
On the "choose Objects" screen, select the "select specific objects" option and check "tables" (pic 2)
on the next screen, select "advanced" and then change the "Script DROP and CREATE" option to "Script DROP and CREATE" (pic 3)
Choose to save script to a new editor window or a file and run as necessary.
this will give you a script that drops and recreates all your tables without the need to worry about debugging or whether you've included everything. While this performs more than just a truncate, the results are the same. Just keep in mind that your auto-incrementing primary keys will start at 0, as opposed to truncated tables which will remember the last value assigned. You can also execute this from code if you don't have access to Management studio on your PreProd or Production environments.
1.
2.
3.
Truncating all of the tables will only work if you don't have any foreign key relationships between your tables, as SQL Server will not allow you to truncate a table with a foreign key.
An alternative to this is to determine the tables with foreign keys and delete from these first, you can then truncate the tables without foreign keys afterwards.
See http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=65341 and http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=72957 for further details.
Don't do this! Really, not a good idea.
If you know which tables you want to truncate, create a stored procedure which truncates them. You can fix the order to avoid foreign key problems.
If you really want to truncate them all (so you can BCP load them for example) you would be just as quick to drop the database and create a new one from scratch, which would have the additional benefit that you know exactly where you are.
An alternative option I like to use with MSSQL Server Deveploper or Enterprise is to create a snapshot of the database immediately after creating the empty schema. At that point you can just keep restoring the database back to the snapshot.
If you want to keep data in a particular table (i.e. a static lookup table) while deleting/truncating data in other tables within the same db, then you need a loop with the exceptions in it. This is what I was looking for when I stumbled onto this question.
sp_MSForEachTable seems buggy to me (i.e. inconsistent behavior with IF statements) which is probably why its undocumented by MS.
declare #LastObjectID int = 0
declare #TableName nvarchar(100) = ''
set #LastObjectID = (select top 1 [object_id] from sys.tables where [object_id] > #LastObjectID order by [object_id])
while(#LastObjectID is not null)
begin
set #TableName = (select top 1 [name] from sys.tables where [object_id] = #LastObjectID)
if(#TableName not in ('Profiles', 'ClientDetails', 'Addresses', 'AgentDetails', 'ChainCodes', 'VendorDetails'))
begin
exec('truncate table [' + #TableName + ']')
end
set #LastObjectID = (select top 1 [object_id] from sys.tables where [object_id] > #LastObjectID order by [object_id])
end
The hardest part of truncating all tables is removing and re-ading the foreign key constraints.
The following query creates the drop & create statements for each constraint relating to each table name in #myTempTable. If you would like to generate these for all the tables, you may simple use information schema to gather these table names instead.
DECLARE #myTempTable TABLE (tableName varchar(200))
INSERT INTO #myTempTable(tableName) VALUES
('TABLE_ONE'),
('TABLE_TWO'),
('TABLE_THREE')
-- DROP FK Contraints
SELECT 'alter table '+quotename(schema_name(ob.schema_id))+
'.'+quotename(object_name(ob.object_id))+ ' drop constraint ' + quotename(fk.name)
FROM sys.objects ob INNER JOIN sys.foreign_keys fk ON fk.parent_object_id = ob.object_id
WHERE fk.referenced_object_id IN
(
SELECT so.object_id
FROM sys.objects so JOIN sys.schemas sc
ON so.schema_id = sc.schema_id
WHERE so.name IN (SELECT * FROM #myTempTable) AND sc.name=N'dbo' AND type in (N'U'))
-- CREATE FK Contraints
SELECT 'ALTER TABLE [PIMSUser].[dbo].[' +cast(c.name as varchar(255)) + '] WITH NOCHECK ADD CONSTRAINT ['+ cast(f.name as varchar(255)) +'] FOREIGN KEY (['+ cast(fc.name as varchar(255)) +'])
REFERENCES [PIMSUser].[dbo].['+ cast(p.name as varchar(255)) +'] (['+cast(rc.name as varchar(255))+'])'
FROM sysobjects f
INNER JOIN sys.sysobjects c ON f.parent_obj = c.id
INNER JOIN sys.sysreferences r ON f.id = r.constid
INNER JOIN sys.sysobjects p ON r.rkeyid = p.id
INNER JOIN sys.syscolumns rc ON r.rkeyid = rc.id and r.rkey1 = rc.colid
INNER JOIN sys.syscolumns fc ON r.fkeyid = fc.id and r.fkey1 = fc.colid
WHERE
f.type = 'F'
AND
cast(p.name as varchar(255)) IN (SELECT * FROM #myTempTable)
I then just copy out the statements to run - but with a bit of dev effort you could use a cursor to run them dynamically.
It is much easier (and possibly even faster) to script out your database, then just drop and create it from the script.
Make an empty "template" database, take a full backup. When you need to refresh, just restore using WITH REPLACE. Fast, simple, bulletproof. And if a couple tables here or there need some base data(e.g. config information, or just basic information that makes your app run) it handles that too.
This is one way to do it... there are likely 10 others that are better/more efficient, but it sounds like this is done very infrequently, so here goes...
get a list of the tables from sysobjects, then loop over those with a cursor, calling sp_execsql('truncate table ' + #table_name) for each iteration.
Run the commented out section once, populate the _TruncateList table with the tables you want truncated, then run the rest of the script. The _ScriptLog table will need to be cleaned up over time if you do this a lot.
You can modify this if you want to do all tables, just put in SELECT name INTO #TruncateList FROM sys.tables. However, you usually don't want to do them all.
Also, this will affect all foreign keys in the database, and you can modify that as well if it's too blunt-force for your application. It's not for my purposes.
/*
CREATE TABLE _ScriptLog
(
ID Int NOT NULL Identity(1,1)
, DateAdded DateTime2 NOT NULL DEFAULT GetDate()
, Script NVarChar(4000) NOT NULL
)
CREATE UNIQUE CLUSTERED INDEX IX_ScriptLog_DateAdded_ID_U_C ON _ScriptLog
(
DateAdded
, ID
)
CREATE TABLE _TruncateList
(
TableName SysName PRIMARY KEY
)
*/
IF OBJECT_ID('TempDB..#DropFK') IS NOT NULL BEGIN
DROP TABLE #DropFK
END
IF OBJECT_ID('TempDB..#TruncateList') IS NOT NULL BEGIN
DROP TABLE #TruncateList
END
IF OBJECT_ID('TempDB..#CreateFK') IS NOT NULL BEGIN
DROP TABLE #CreateFK
END
SELECT Scripts = 'ALTER TABLE ' + '[' + OBJECT_NAME(f.parent_object_id)+ ']'+
' DROP CONSTRAINT ' + '[' + f.name + ']'
INTO #DropFK
FROM .sys.foreign_keys AS f
INNER JOIN .sys.foreign_key_columns AS fc
ON f.OBJECT_ID = fc.constraint_object_id
SELECT TableName
INTO #TruncateList
FROM _TruncateList
SELECT Scripts = 'ALTER TABLE ' + const.parent_obj + '
ADD CONSTRAINT ' + const.const_name + ' FOREIGN KEY (
' + const.parent_col_csv + '
) REFERENCES ' + const.ref_obj + '(' + const.ref_col_csv + ')
'
INTO #CreateFK
FROM (
SELECT QUOTENAME(fk.NAME) AS [const_name]
,QUOTENAME(schParent.NAME) + '.' + QUOTENAME(OBJECT_name(fkc.parent_object_id)) AS [parent_obj]
,STUFF((
SELECT ',' + QUOTENAME(COL_NAME(fcP.parent_object_id, fcp.parent_column_id))
FROM sys.foreign_key_columns AS fcP
WHERE fcp.constraint_object_id = fk.object_id
FOR XML path('')
), 1, 1, '') AS [parent_col_csv]
,QUOTENAME(schRef.NAME) + '.' + QUOTENAME(OBJECT_NAME(fkc.referenced_object_id)) AS [ref_obj]
,STUFF((
SELECT ',' + QUOTENAME(COL_NAME(fcR.referenced_object_id, fcR.referenced_column_id))
FROM sys.foreign_key_columns AS fcR
WHERE fcR.constraint_object_id = fk.object_id
FOR XML path('')
), 1, 1, '') AS [ref_col_csv]
FROM sys.foreign_key_columns AS fkc
INNER JOIN sys.foreign_keys AS fk ON fk.object_id = fkc.constraint_object_id
INNER JOIN sys.objects AS oParent ON oParent.object_id = fkc.parent_object_id
INNER JOIN sys.schemas AS schParent ON schParent.schema_id = oParent.schema_id
INNER JOIN sys.objects AS oRef ON oRef.object_id = fkc.referenced_object_id
INNER JOIN sys.schemas AS schRef ON schRef.schema_id = oRef.schema_id
GROUP BY fkc.parent_object_id
,fkc.referenced_object_id
,fk.NAME
,fk.object_id
,schParent.NAME
,schRef.NAME
) AS const
ORDER BY const.const_name
INSERT INTO _ScriptLog (Script)
SELECT Scripts
FROM #CreateFK
DECLARE #Cmd NVarChar(4000)
, #TableName SysName
WHILE 0 < (SELECT Count(1) FROM #DropFK) BEGIN
SELECT TOP 1 #Cmd = Scripts
FROM #DropFK
EXEC (#Cmd)
DELETE #DropFK WHERE Scripts = #Cmd
END
WHILE 0 < (SELECT Count(1) FROM #TruncateList) BEGIN
SELECT TOP 1 #Cmd = N'TRUNCATE TABLE ' + TableName
, #TableName = TableName
FROM #TruncateList
EXEC (#Cmd)
DELETE #TruncateList WHERE TableName = #TableName
END
WHILE 0 < (SELECT Count(1) FROM #CreateFK) BEGIN
SELECT TOP 1 #Cmd = Scripts
FROM #CreateFK
EXEC (#Cmd)
DELETE #CreateFK WHERE Scripts = #Cmd
END
It is a little late but it might help someone.
I created a procedure sometimes back which does the following using T-SQL:
Store all constraints in a Temporary table
Drop All Constraints
Truncate all tables with exception of some tables, which does not need truncation
Recreate all Constraints.
I have listed it on my blog here
I do not see why clearing data would be better than a script to drop and re-create each table.
That or keep a back up of your empty DB and restore it over old one
Before truncating the tables you have to remove all foreign keys. Use this script to generate final scripts to drop and recreate all foreign keys in database. Please set the #action variable to 'CREATE' or 'DROP'.
select 'delete from ' +TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_TYPE='BASE TABLE'
where result come.
Copy and paste on query window and run the command

Resources