I got a data base trigger after table create.
CREATE TRIGGER tr_Timestamps_TableTriggersCreation
ON DATABASE
AFTER CREATE_TABLE
AS
BEGIN
SET NOCOUNT ON
DECLARE #tableName SYSNAME
DECLARE #schemaName SYSNAME = NULL
DECLARE #totalRows INT = 0;
SELECT #tableName = EVENTDATA().value('(/EVENT_INSTANCE/ObjectName)[1]','SYSNAME')
SELECT TOP 1 #schemaName = s.name
FROM sys.tables t
JOIN sys.columns c ON c.object_id = t.object_id
JOIN sys.schemas s ON s.schema_id = t.schema_id
WHERE t.name = #tableName
AND c.name = 'ID'
IF (#schemaName != '')
BEGIN
EXEC u_general.sp_Timestamps_TriggerForTableCreation #tableName, #schemaName, 'I'
EXEC u_general.sp_Timestamps_TriggerForTableCreation #tableName, #schemaName, 'U'
END
The idea behind it is to create 2 trigger for each table which is being created on that database.
My problem is as follow,
When someone uses the MSSQL 'editor' and uses the 'Design' option instead of writing a script for making changes such as marking a column for 'Allow Null or not', change the data type etc...
My Data base trigger counts it as a new table creation and launches the procedure which create the triggers for that table.
The end result is that it tries to create those triggers again and i get an error message that those triggers already exist.
ALTER PROCEDURE [u_general].[sp_Timestamps_TriggerForTableCreation] ( #tableName sysname, #schemaName sysname, #actionType char(1))
AS
DECLARE #TrigerName NVARCHAR(50)
DECLARE #AfterActionName NVARCHAR(50)
IF #actionType = 'I'
BEGIN
SET #TrigerName = 'tr_Timestamps_CaptureAfterInsert_' + #tableName
SET #AfterActionName = 'INSERT'
END
ELSE -- 'U'
BEGIN
SET #TrigerName = 'tr_Timestamps_CaptureAfterUpdate_' + #tableName
SET #AfterActionName = 'UPDATE'
END
DECLARE #SQLCommand nvarchar(max)=
'CREATE TRIGGER ' + #TrigerName +'
ON ' + #schemaName + '.' + #tableName +
' AFTER '+ #AfterActionName +'
AS
DECLARE #auditBody XML
DECLARE #RowID int
SELECT #RowID = INSERTED.ID FROM INSERTED
SELECT #auditBody =
''<Timestamps_Request>
<DataBaseName>'' + DB_NAME() + ''</DataBaseName>
<SchemaName>'' + ''' + #schemaName + ''' + ''</SchemaName>
<TableName>'' + ''' + #tableName + '''+ ''</TableName>
<RowID>'' + CAST(#RowID AS NVARCHAR(30)) + ''</RowID>
<Action>'' + '''+#actionType+''' + ''</Action>
</Timestamps_Request>''
EXEC u_general.sp_Timestamps_SendBrokerMessage #FromService = ''Timestamps_RequestService'',
#ToService = ''Timestamps_ProcessingService'',
#Contract = ''Timestamps_Contract'',
#MessageType = ''Timestamps_Request'',
#MessageBody = #auditBody ';
EXEC sp_executeSQL #SQLCommand
My question is,
What can i do to make sure that it wont happen every time someone decides to use the designer for 'altering' a table?
P.S. From my understanding it has something to do with the SSMS (causes drop and create? ) and the way it works, and this is why i dont have this issue while using a script to modify the table instead of the MSSQL designer.
Quick Note before direct answer.
Use DDL Events with CREATE_TABLE and Confirm you Don't using Alter_TABLE within your Trigger definitions, because CREATE_TABLE and Alter_TABLE is totally separated events.
Follow the next Demo for more Details.
Demo:-
Create table table1 (col1 int, col2 nvarchar(10) not null )
go
Create TRIGGER NoCreateNewTables ON DATABASE
FOR CREATE_TABLE
AS
Print 'Prevent Table Creation'
BEGIN
ROLLBACK;
END
GO
Lets Alter Table1 Via next:
ALTER TABLE table1 ALTER COLUMN col2 nvarchar(10) NULL
Result:-
Lets Create new table Table2 Via next:
Create table table2 (col1 int, col2 nvarchar(10) not null )
Result:-
What about SSMS
The direct answer starts here
SQL Server drops and recreates the tables while using SSMS designer in some cases:
Common cases:-
Add a new column.
Change the Allow Nulls setting for a column.
Change the column order in the table.
Change the column data type.
After some investigation , I noticed the Object_Name that altered via SSMS designer Starts with Tmp_.
so according to this info we can prevent alter table via SSMS designer by Create Trigger for Preventing altering table from SSMS while table recreated.
Demo:-
/* Create Trigger for Preventing altering table Via SSMS while table recreated */
Create TRIGGER TrgPreventAlterTableIfTableRecreatedViaSSMSDesign ON DATABASE
FOR CREATE_TABLE
AS
BEGIN
DECLARE
#eventInfo XML,
#ObjectName varchar(100)
SET
#eventInfo = EVENTDATA()
select #ObjectName = CONVERT(SYSNAME, #eventInfo.query('data(/EVENT_INSTANCE/ObjectName)'))
if (Left(#ObjectName,3) = 'Tmp')
begin
exec sp_addmessage 50001, 16,
N'Cannot modify Table Via SSMS, use [Alter Table] Code instead';
RAISERROR(50001,16,1)
exec sp_dropmessage 50001
rollback;
end
END
Now Try alter Table1 Via SSMS designer from NULL to NOT NULL
The next pop messages will be raised:-
Related
I'm adding scripts to an SSDT project to manage the addition/update of data from static data tables. Some of these tables reference each other, so I need to be able to shut down the constraints during the update so that I can let the data sit in an inconsistent state until all the scripts are run (I've got a file for table A, and a separate one for Table B).
Once completed, I need to re-enable all the constraints (and let the system check the data to ensure it's consistent). The caveat, is that for various reasons some of the constraints are currently disabled - and I need to ensure that they restore back to the state they were in before my script.
I can't seem to find a view/table that lists the current status of the FK constraints.
Is there any way to have SSDT publish do this automatically? Or if not, can anyone recommend a good solution for doing this?
In the end, I used a combination of sys.Foreign_Keys and sys.check_constraints, since the disable all command disabled both of them. I'm recording the status of the constraints prior to doing my work, then re-enabling them back to the original state at the end.
If OBJECT_ID('tempdb..#tempConstraints') is not null Drop Table #tempConstraints;
GO
IF (SELECT OBJECT_ID('tempdb..#tmpScriptErrors')) IS NOT NULL DROP TABLE #tmpScriptErrors
GO
CREATE TABLE #tmpScriptErrors (Error int)
GO
Create Table #tempConstraints
(
ConstraintName nVarchar(200),
TableName nVarchar(200),
SchemaName nVarchar(200),
IsNotTrusted bit
);
GO
Begin Tran
Insert into #tempConstraints (ConstraintName, TableName, SchemaName, IsNotTrusted)
Select K.name, object_name(K.parent_object_id), SCHEMA_NAME(T.schema_id), K.Is_Not_Trusted
FROM sys.foreign_keys K
Inner Join sys.tables T on K.parent_object_id = T.object_id
Where is_disabled = 0
Union all
Select K.name, object_name(K.parent_object_id), SCHEMA_NAME(T.schema_id), K.Is_Not_Trusted
from sys.check_constraints K
Inner Join sys.tables T on K.parent_object_id = T.object_id
Where is_disabled = 0
--Disable the Constraints.
Print 'Disabling Constraints'
Exec sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT ALL';
----------------------------------------------------------------------------------------
--Do Work Here
----------------------------------------------------------------------------------------
Declare #name nvarchar(200);
Declare #table nvarchar(200);
Declare #schema nvarchar(200);
Declare #script nvarchar(max);
Declare #NotTrusted bit;
Declare constraints_cursor CURSOR FOR
Select ConstraintName, TableName, SchemaName, IsNotTrusted
From #tempConstraints;
Open constraints_cursor;
Fetch Next from constraints_cursor
into #name, #table, #schema, #NotTrusted;
While ##FETCH_STATUS = 0
Begin
--Restore each of the Constraints back to exactly the state they were in prior to disabling.
If #NotTrusted = 1
Set #script = 'ALTER TABLE [' + #schema + '].[' + #table + '] WITH NOCHECK CHECK CONSTRAINT [' + #name + ']';
Else
Set #script = 'ALTER TABLE [' + #schema + '].[' + #table + '] WITH CHECK CHECK CONSTRAINT [' + #name + ']';
exec sp_executesql #script;
If ##ERROR <> 0
Begin
INSERT INTO #tmpScriptErrors (Error)
VALUES (1);
End
Fetch Next from constraints_cursor
into #name, #table, #schema, #NotTrusted;
End
Close constraints_cursor;
Deallocate constraints_cursor;
If exists (Select 'x' from #tmpScriptErrors)
ROLLBACK TRAN;
Else
COMMIT TRAN;
Drop table #tmpScriptErrors
GO
Drop table #tempConstraints
GO
I have several databases in a Sql Server 2008 R2 instance. Some of those databases have a full-text enabled table. The name of the full-text table is equal for all databases, but the databases have different names and they are created on demand (I never know what databases exists and what does not).
The thing is: I need to query all catalogs in all databases to check if a population is done, but I have no idea how many databases I have (of course I know, but they are created on demand as I said). The script must query all databases and check if a population is done in a table (which the name I know because it never changes besides the name of the database that does change)
I have seen many people using things like:
sys.fulltext_catalogs
But it does not work if i am using the master database for example.
Any ideas?
Edit: Here is more complete code with a cursor, a full list of databases (even those without catalogs), and the right catalog view name:
SET NOCOUNT ON;
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql += ' UNION ALL
SELECT [name] = ''' + QUOTENAME(name) + ''',
catalog_name = name COLLATE Latin1_General_CI_AI,
is_importing
FROM ' + QUOTENAME(name) + '.sys.fulltext_catalogs'
FROM sys.databases WHERE database_id > 4;
SET #sql = 'SELECT [database] = d.name,
s.catalog_name,
s.is_importing
FROM sys.databases AS d
LEFT OUTER JOIN (' + STUFF(#sql, 1, 10, '') + ') AS s
ON QUOTENAME(d.name) = s.name
WHERE d.database_id > 4;';
CREATE TABLE #temp(db SYSNAME, catalog_name NVARCHAR(255), is_importing BIT);
INSERT #temp EXEC sp_executesql #sql;
DECLARE #db SYSNAME, #catalog_name NVARCHAR(255), #is_importing BIT;
DECLARE c CURSOR LOCAL STATIC FORWARD_ONLY READ_ONLY
FOR SELECT db, catalog_name, is_importing FROM #temp;
OPEN c;
FETCH NEXT FROM c INTO #db, #catalog_name, #is_importing;
WHILE ##FETCH_STATUS = 0
BEGIN
IF #catalog_name IS NULL
BEGIN
PRINT 'No catalogs for ' + #db;
END
ELSE
BEGIN
IF #is_importing = 1
BEGIN
PRINT 'Do something to ' + #db
+ '(importing)';
END
ELSE
BEGIN
PRINT #db + ' is not importing.';
END
END
FETCH NEXT FROM c INTO #db, #catalog_name, #is_importing;
END
CLOSE c;
DEALLOCATE c;
DROP TABLE #temp;
This gives you a complete list of used catalogs.
CREATE TABLE #info (
databasename VARCHAR(128)
, [Fulltext Catalog Name] VARCHAR(128));
SET NOCOUNT ON;
INSERT INTO #info
EXEC sp_MSforeachdb 'use ?
SELECT ''?''
, name
FROM sys.fulltext_catalogs;'
SELECT * FROM #info
-- get rid of temp table
DROP TABLE #info;
We have a large number of views in an inherited database which some of them are missing dependencies (table or even other views)?
What's the best way to identify the views which have missing dependencies?
DECLARE #stmt nvarchar(max) = ''
DECLARE #vw_schema NVARCHAR(255)
DECLARE #vw_name varchar(255)
IF OBJECT_ID('tempdb..#badViews') IS NOT NULL DROP TABLE #badViews
IF OBJECT_ID('tempdb..#nulldata') IS NOT NULL DROP TABLE #nulldata
CREATE TABLE #badViews
(
[schema] NVARCHAR(255),
name VARCHAR(255),
error NVARCHAR(MAX)
)
CREATE TABLE #nullData
(
null_data varchar(1)
)
DECLARE tbl_cursor CURSOR LOCAL FORWARD_ONLY READ_ONLY
FOR SELECT name, SCHEMA_NAME(schema_id) AS [schema]
FROM sys.objects
WHERE type='v'
OPEN tbl_cursor
FETCH NEXT FROM tbl_cursor
INTO #vw_name, #vw_schema
WHILE ##FETCH_STATUS = 0
BEGIN
SET #stmt = 'SELECT TOP 1 * FROM [' + #vw_schema + N'].[' + #vw_name + ']'
BEGIN TRY
INSERT INTO #nullData EXECUTE sp_executesql #stmt
END TRY
BEGIN CATCH
IF ERROR_NUMBER() != 213 BEGIN
INSERT INTO #badViews (name, [schema], error) values (#vw_name, #vw_schema, ERROR_MESSAGE())
END
END CATCH
FETCH NEXT FROM tbl_cursor
INTO #vw_name, #vw_schema
END
CLOSE tbl_cursor -- free the memory
DEALLOCATE tbl_cursor
SELECT * FROM #badViews
DROP TABLE #badViews
DROP TABLE #nullData
Update 2017
Updated the answer as per #robyaw's answer.
I've also fixed a bug in it for the computed values in the select statements. It seems SELECT TOP 1 NULL from vwTest doesn't throw an error when vwTest contains a column like let's say 1/0 as [Col1], but SELECT TOP 1 * from vwTest it does throw an exception.
Update 2018
Fix false positives for views and or schema that contain special characters in their name. Thanks to #LucasAyala
Adrian Iftode's solution is good, but fails if there are views that are not associated with the default schema. The following is a revised version of his solution that takes schema into account, whilst also providing error information against each failing view (tested on SQL Server 2012):
DECLARE #stmt NVARCHAR(MAX) = '';
DECLARE #vw_schema NVARCHAR(255);
DECLARE #vw_name NVARCHAR(255);
CREATE TABLE #badViews
(
[schema] NVARCHAR(255)
, name NVARCHAR(255)
, error NVARCHAR(MAX)
);
CREATE TABLE #nullData
(
null_data VARCHAR(1)
);
DECLARE tbl_cursor CURSOR FORWARD_ONLY READ_ONLY
FOR
SELECT
SCHEMA_NAME(schema_id) AS [schema]
, name
FROM
sys.objects
WHERE
[type] = 'v';
OPEN tbl_cursor;
FETCH NEXT FROM tbl_cursor INTO #vw_schema, #vw_name;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #stmt = CONCAT(N'SELECT TOP 1 NULL FROM ', #vw_schema, N'.', #vw_name);
BEGIN TRY
-- silently execute the "select from view" query
INSERT INTO #nullData EXECUTE sp_executesql #stmt;
END TRY
BEGIN CATCH
INSERT INTO #badViews ([schema], name, error)
VALUES (#vw_schema, #vw_name, ERROR_MESSAGE());
END CATCH
FETCH NEXT FROM tbl_cursor INTO #vw_schema, #vw_name;
END
CLOSE tbl_cursor;
DEALLOCATE tbl_cursor;
-- print the views with errors when executed
SELECT * FROM #badViews;
DROP TABLE #badViews;
DROP TABLE #nullData;
Try this
Call sp_refreshsqlmodule on all non-schema bound stored procedures:
DECLARE #template AS varchar(max)
SET #template = 'PRINT ''{OBJECT_NAME}''
EXEC sp_refreshsqlmodule ''{OBJECT_NAME}''
'
DECLARE #sql AS varchar(max)
SELECT #sql = ISNULL(#sql, '') + REPLACE(#template, '{OBJECT_NAME}',
QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME))
FROM INFORMATION_SCHEMA.ROUTINES
WHERE OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME)),
N'IsSchemaBound') IS NULL
OR OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME)),
N'IsSchemaBound') = 0
EXEC (
#sql
)
This works for all views, functions and SPs. Schemabound objects won't have problems and this can't be run on them, that's why they are excluded.
Note that it is still possible for SPs to fail at runtime due to missing tables - this is equivalent to attempting to ALTER the procedure.
Note also that just like ALTER, it will lose extended properties on UDFs - I script these off and restore them afterwards.
If you're using SQL Server 2005 or 2008, you could import the project in to Visual Studio 2008 or 2010 and analyze broken dependencies from the Visual Studio project
I would backup the database, restore it on my dev machine, create a script with all the views in a new window in management server, drop all views and try executing the script. Whenever a view is "corrupt", the execution will fail with an error message, e.g. Not existing table or column.
I have created a stored procedure that will drop a table if it exists in a database. When running the stored procedure with EXEC, I am getting the following error:
Msg 203, Level 16, State 2, Procedure
sp_DropIfExists, Line 13 The name 'IF
EXISTS(SELECT 1 FROM sys.objects WHERE
OBJECT_ID = OBJECT_ID(N'table_name')
AND type = (N'U')) DROP TABLE
[table_name]' is not a valid
identifier.
However if i copy and paste the T-SQL that is generated into management studio, it seems to be running fine. Can someone explain why this is not valid? The fix would be nice, but I am really after the Why primarily, The How would be nice to though! Thanks in advance.
ALTER PROCEDURE [dbo].[sp_DropIfExists](#tableName VARCHAR(255))
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL VARCHAR(MAX);
SET #SQL = 'IF EXISTS(SELECT 1 FROM sys.objects WHERE OBJECT_ID = OBJECT_ID(N''' + #tableName + ''') AND type = (N''U'')) DROP TABLE [' + #tableName + ']'
PRINT #SQL;
EXEC #SQL;
END
you can use sp_execute
sp_executesql #SQL
for more information msdn document link
Not sure if this will solve your problems but you would be better placing you check is a function like so
CREATE FUNCTION [dbo].[TableExists]
(
#TableName VarChar(100)
)
RETURNS BIT
AS
BEGIN
DECLARE #TableExists BIT
IF EXISTS(SELECT name FROM sysobjects a
WHERE a.name = #TableName
AND a.xtype = 'U')
SET #TableExists = 1
ELSE
SET #TableExists = 0
RETURN #TableExists
END
Then you can use it as follows.
IF dbo.TableExists('[table_name]') = 1
DROP TABLE [table_name]
Try this and let me know if you still get the same error.
--ALTER (if procedure exists)
CREATE PROCEDURE sp_dropifexists (#tableName VARCHAR(255))
AS
BEGIN
DECLARE #SQL VARCHAR(MAX);
SET #SQL = 'IF EXISTS(SELECT 1 FROM sys.objects WHERE OBJECT_ID = OBJECT_ID(N''' + #tableName + ''') AND type = (N''U'')) DROP TABLE [' + #tableName + ']'
--if write EXEC #SQL without parentheses sql says Error: is not a valid identifier
EXEC (#SQL);
END
--test procedure
exec sp_DropIfExists 'table'
EXEC #SQL should be EXEC (#SQL). (But #maycil's suggestion is correct too.)
Turns out, without the parentheses #SQL's value is interpreted as the name of a stored procedure to execute, not as a script. (I didn't know that before, but I made a small test to verify that it is indeed so.)
How can I drop a table with all its dependencies [SPs, Views, etc.] (Microsoft SQL Server) without knowing its dependencies upfront? I know I can display all dependencies in Mangement Studio but I'm searching for utility script that I could simply speficy an object and it would drop this object with all its dependencies.
The best thing to do it is "Generate scripts for Drop"
Select Database -> Right Click -> Tasks -> Generate Scripts - will open wizard for generating scripts
Select the database -> next
Set option 'Script to create' to true (want to create)
Set option 'Script to Drop' to true (want to drop)
Set option 'Generate script for dependent object' to true -> Next
Select the Check box to select objects wish to create script
Select the choice to write script (File, New window, Clipboard)
Execute the script
This way we can customize our script i.e., we can do scripting for selected objects of a database.
I hope this will help you!
Best Wishes, JP
You can use Sp_Depends to find the dependencies. With that you can modify the script from this answer Maybe someone less lazy than me will do that for you.
Note: Each object of course could have its own dependencies so you'll need to process them as well.
Delete a SQL object using its schema-qualified name. For tables, the constraints are dropped first.
Errors are ignored.
create procedure [dbo].[spDropObject] (#fullname nvarchar(520))
as
begin
begin try
declare #type nvarchar(5)
declare #resolvedFullname nvarchar(520)
declare #resolvedName nvarchar(255)
set #type = null
set #resolvedFullname = null
set #resolvedName = null
--find the object
select
#type = o.[type]
,#resolvedFullname = '[' + object_schema_name(o.id) + '].[' + o.[name] + ']'
,#resolvedName = '[' + o.[name] + ']'
from dbo.sysobjects o
where id = object_id(#fullname)
--PROCEDURE
if(#type = 'P')
begin
exec('drop procedure ' + #resolvedFullname);
return;
end
--VIEW
if(#type = 'V')
begin
exec('drop view ' + #resolvedFullname);
return;
end
--FUNCTION
if(#type = 'FN' or #type = 'TF')
begin
exec('drop function ' + #resolvedFullname);
return;
end
--TRIGGER
if(#type = 'TF')
begin
exec('drop trigger ' + #resolvedFullname);
return;
end
--CONSTRAINT
if(#type = 'C' or #type = 'UQ' or #type = 'D' or #type = 'F' or #type = 'PK' or #type = 'K')
begin
declare #fullTablename nvarchar(520);
set #fullTablename = null
--find the contraint's table
select #fullTablename ='[' + object_schema_name(t.[object_id]) + '].[' + t.[Name] + ']'
from sys.tables t
join sys.schemas s on t.schema_id = s.schema_id
where t.object_id = (select parent_obj from dbo.sysobjects where id = object_id(#resolvedFullname))
exec('alter table ' + #fullTablename + ' drop constraint ' + #resolvedName);
return;
end
--TABLE (drop all constraints then drop the table)
if(#type = 'U')
begin
--find FK references to the table
declare #fktab table([Name] nvarchar(255))
insert #fktab
select
[Name] = '[' + object_name(fkc.[constraint_object_id]) + ']'
/*
,[Parent] = '[' + object_schema_name(fkc.[parent_object_id]) + '].[' + object_name(fkc.[parent_object_id]) + ']'
,[Ref] = '[' + object_schema_name(fkc.[referenced_object_id]) + '].[' + object_name(fkc.[referenced_object_id]) + ']'
*/
from sys.foreign_key_columns as fkc
where referenced_object_id = object_id(#resolvedFullname)
order by [Name]
--iterate FKs
while(1=1)
begin
declare #constraint nvarchar(255)
set #constraint = null
select top 1
#constraint = [Name]
from #fktab
if(#constraint is not null)
begin
--drop FK constraint
exec [dbo].[spDropObject] #constraint;
delete from #fktab where [Name] = #constraint --remove current record from working table
end
else break;
end
--find constraints for table
declare #constraintTab table ([Name] nvarchar(255));
insert #constraintTab
select [name]
from sys.objects
where parent_object_id = object_id(#resolvedFullname)
order by [name]
--iterate constraints
while(1=1)
begin
set #constraint = null;
select top 1 #constraint = [Name] from #constraintTab
if(#constraint is not null)
begin
--drop constraint
exec [dbo].[spDropObject] #constraint;
delete from #constraintTab where [Name] = #constraint --remove current record from working table
end
else break;
end
--drop table
exec('drop table ' + #resolvedFullname);
return;
end
end try
begin catch
declare #message nvarchar(max)
set #message = error_message( ) ;
print #message
end catch
end
In my case, I specifically wanted to drop a specified table and the tables that depend on that table. It wasn't useful to me to only drop the foreign key constraints that reference it. I wrote a stored procedure to do this
CREATE PROCEDURE DropDependentTables (
#tableName NVARCHAR(64))
AS
-- Find and drop all tables that depend on #tableName
WHILE EXISTS(SELECT *
FROM sys.foreign_keys
WHERE OBJECT_NAME(referenced_object_id) = #tableName AND
OBJECT_NAME(parent_object_id) != #tableName)
BEGIN
DECLARE #dependentTableName NVARCHAR(64)
SELECT TOP 1 #dependentTableName = OBJECT_NAME(parent_object_id)
FROM sys.foreign_keys
WHERE OBJECT_NAME(referenced_object_id) = #tableName AND
OBJECT_NAME(parent_object_id) != #tableName
EXEC DropDependentTables #dependentTableName
END
I'm going to leave a late answer (after around 10 years). I hope you'll find it handy.
In our company, we use this script to properly delete database tables. For each table, we first drop the dependencies (REFERENTIAL_CONSTRAINTS) then delete the table itself.
USE [database-name]
DECLARE #Sql NVARCHAR(500) DECLARE #Cursor CURSOR
SET #Cursor = CURSOR FAST_FORWARD FOR
SELECT DISTINCT sql = 'ALTER TABLE [' + tc2.TABLE_SCHEMA + '].[' + tc2.TABLE_NAME + '] DROP [' + rc1.CONSTRAINT_NAME + '];'
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc1
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc2 ON tc2.CONSTRAINT_NAME =rc1.CONSTRAINT_NAME
OPEN #Cursor FETCH NEXT FROM #Cursor INTO #Sql
WHILE (##FETCH_STATUS = 0)
BEGIN
Exec sp_executesql #Sql
FETCH NEXT FROM #Cursor INTO #Sql
END
CLOSE #Cursor DEALLOCATE #Cursor
GO
EXEC sp_MSforeachtable 'DROP TABLE ?'
GO
The credit goes to a colleague of mine, Abolfazl Najafzade, for the script.