SQL Server does not help to easily determine the dependencies between tables. This research presents the parent table and the child tables and columns used.
https://msdn.microsoft.com/en-us/library/ms179610.aspx http://stackoverflow.com/questions/925738/how-to-find-foreign-key-dependencies-in-sql-server
well, however, we have many databases with bad design that didn’t have foreign keys defined but that did have related data.
1
2SELECT
3 ROW_NUMBER() OVER (ORDER BY ForeignKeyTable.name) as rownumber
4 , PARENTSchemas.name AS PARENT_SchemaName
5 , PARENTObject.name AS PARENT_TableName
6 , PARENTColumn.name AS PARENT_ColumnName
7 --, PARENTColumn.column_id AS PARENT_ColumnPosition
8 , ForeignKeySchema.name AS FOREIGNKEY_SchemaName
9 , ForeignKeyTable.name AS FOREIGNKEY_TableName
10 , ForeignKeyColumn.name AS FOREIGNKEY_ColumnName
11 --, sys.foreign_key_columns.referenced_object_id AS PARENT_OBJECT_ID
12 --, sys.foreign_key_columns.referenced_column_id AS PARENT_COLUMN_ID
13 --, sys.foreign_key_columns.constraint_object_id
14 --, sys.foreign_key_columns.constraint_column_id
15 --, sys.foreign_key_columns.parent_object_id AS FOREIGNKEY_OBJECT_ID
16 --, sys.foreign_key_columns.parent_column_id AS FOREIGNKEY_COLUMN_ID
17 , sys.foreign_keys.is_disabled
18FROM
19 sys.foreign_key_columns INNER JOIN
20 sys.foreign_keys ON sys.foreign_key_columns.constraint_object_id = sys.foreign_keys.object_id INNER JOIN
21 sys.objects AS PARENTObject ON sys.foreign_key_columns.referenced_object_id = PARENTObject.object_id INNER JOIN
22 sys.schemas AS PARENTSchemas ON PARENTObject.schema_id = PARENTSchemas.schema_id INNER JOIN
23 sys.columns AS ForeignKeyColumn ON sys.foreign_key_columns.parent_object_id = ForeignKeyColumn.object_id AND
24 sys.foreign_key_columns.parent_column_id = ForeignKeyColumn.column_id INNER JOIN
25 sys.objects AS ForeignKeyTable ON sys.foreign_key_columns.parent_object_id = ForeignKeyTable.object_id INNER JOIN
26 sys.columns AS PARENTColumn ON sys.foreign_key_columns.referenced_object_id = PARENTColumn.object_id AND
27 sys.foreign_key_columns.referenced_column_id = PARENTColumn.column_id INNER JOIN
28 sys.schemas AS ForeignKeySchema ON ForeignKeyTable.schema_id = ForeignKeySchema.schema_id
29WHERE (PARENTObject.type = 'U')
This example of use is not a perfect solution. Considerations and compromises that limit this solution:
* Tables can not have self-reference.
* The selection conditions are repeated and are not an example of performance. I thought to use temporary tables but I do not have time and patience.
The SQL code is created to be used to create an initial version.
1
2DROP PROCEDURE sDBACascateDelete
3Go
4CREATE PROCEDURE sDBACascateDelete
5(
6 @schemaname nvarchar(100)
7 , @tablename nvarchar(100)
8 , @where nvarchar(1024)
9 , @recursive int = 1
10
11)
12AS
13BEGIN
14
15SET NOCOUNT ON
16
17DECLARE
18 @schemanameNEW nvarchar(100)
19 , @tablenameNEW nvarchar(100)
20 , @whereNEW nvarchar(1024)
21DECLARE @SQL nvarchar(max);
22DECLARE @SQL1 nvarchar(max);
23DECLARE @SQLTODelete nvarchar(max);
24DECLARE @rownumber INT;
25
26DECLARE @TMP TABLE (
27 [rownumber] [bigint] NULL,
28 [PARENT_SchemaName] [sysname] NOT NULL,
29 [PARENT_TableName] [sysname] NOT NULL,
30 [PARENT_ColumnName] [sysname] NULL,
31 [PARENT_ColumnPosition] [int] NOT NULL,
32 [FOREIGNKEY_SchemaName] [sysname] NOT NULL,
33 [FOREIGNKEY_TableName] [sysname] NOT NULL,
34 [FOREIGNKEY_ColumnName] [sysname] NULL,
35 [PARENT_OBJECT_ID] [int] NOT NULL,
36 [PARENT_COLUMN_ID] [int] NOT NULL,
37 [constraint_object_id] [int] NOT NULL,
38 [constraint_column_id] [int] NOT NULL,
39 [FOREIGNKEY_OBJECT_ID] [int] NOT NULL,
40 [FOREIGNKEY_COLUMN_ID] [int] NOT NULL,
41 [is_disabled] [bit] NOT NULL
42);
43
44SET @SQL = char(13)+char(10);
45SET @SQL = '';
46SET @SQL = 'DELETE FROM ['+@schemaname+'].['+@tablename+'] WHERE '+@where+@SQL + ';';
47SET @SQLTODelete = ' FROM ['+@schemaname+'].['+@tablename+'] WHERE '+@where;
48
49INSERT INTO @TMP
50SELECT
51 ROW_NUMBER() OVER (ORDER BY ForeignKeyTable.name) as rownumber
52 , PARENTSchemas.name AS PARENT_SchemaName
53 , PARENTObject.name AS PARENT_TableName
54 , PARENTColumn.name AS PARENT_ColumnName
55 , PARENTColumn.column_id AS PARENT_ColumnPosition
56 , ForeignKeySchema.name AS FOREIGNKEY_SchemaName
57 , ForeignKeyTable.name AS FOREIGNKEY_TableName
58 , ForeignKeyColumn.name AS FOREIGNKEY_ColumnName
59 , sys.foreign_key_columns.referenced_object_id AS PARENT_OBJECT_ID
60 , sys.foreign_key_columns.referenced_column_id AS PARENT_COLUMN_ID
61 , sys.foreign_key_columns.constraint_object_id
62 , sys.foreign_key_columns.constraint_column_id
63 , sys.foreign_key_columns.parent_object_id AS FOREIGNKEY_OBJECT_ID
64 , sys.foreign_key_columns.parent_column_id AS FOREIGNKEY_COLUMN_ID
65 , sys.foreign_keys.is_disabled
66FROM
67 sys.foreign_key_columns INNER JOIN
68 sys.foreign_keys ON sys.foreign_key_columns.constraint_object_id = sys.foreign_keys.object_id INNER JOIN
69 sys.objects AS PARENTObject ON sys.foreign_key_columns.referenced_object_id = PARENTObject.object_id INNER JOIN
70 sys.schemas AS PARENTSchemas ON PARENTObject.schema_id = PARENTSchemas.schema_id INNER JOIN
71 sys.columns AS ForeignKeyColumn ON sys.foreign_key_columns.parent_object_id = ForeignKeyColumn.object_id AND
72 sys.foreign_key_columns.parent_column_id = ForeignKeyColumn.column_id INNER JOIN
73 sys.objects AS ForeignKeyTable ON sys.foreign_key_columns.parent_object_id = ForeignKeyTable.object_id INNER JOIN
74 sys.columns AS PARENTColumn ON sys.foreign_key_columns.referenced_object_id = PARENTColumn.object_id AND
75 sys.foreign_key_columns.referenced_column_id = PARENTColumn.column_id INNER JOIN
76 sys.schemas AS ForeignKeySchema ON ForeignKeyTable.schema_id = ForeignKeySchema.schema_id
77WHERE (PARENTObject.type = 'U')
78AND PARENTSchemas.name = @schemaname
79AND PARENTObject.name = @tablename
80
81-- select * from @TMP
82
83DELETE FROM @TMP WHERE FOREIGNKEY_SchemaName = @tablename AND FOREIGNKEY_TableName = @schemaname;
84--SELECT * FROM #TMP;
85
86DECLARE @n INT = 26;
87
88DECLARE @PARENT_tableName AS NVARCHAR(MAX);
89WHILE (@recursive=1 AND (SELECT count(*) FROM @TMP)>0)
90BEGIN
91
92 ----SELECT TOP 1 @PARENT_tableName = PARENT_tableName, @sql1 = 'DELETE FROM ' + PARENT_tableName FROM #TMP WHERE FOREIGNKEY_TableName = @tablename AND FOREIGNKEY_SchemaName = @schemaname;
93 ----SELECT TOP 1 * FROM #TMP WHERE FOREIGNKEY_TableName = @tablename AND FOREIGNKEY_SchemaName = @schemaname;
94 --SELECT @sql1 = 'DELETE FROM ['+FOREIGNKEY_SchemaName+'].['+FOREIGNKEY_TableName+'] WHERE ' + FOREIGNKEY_ColumnName + ' in (SELECT '+PARENT_ColumnName+' FROM ['+PARENT_SchemaName+'].['+PARENT_TableName+'])'
95 --FROM #TMP WHERE PARENT_TableName = @tablename AND PARENT_SchemaName = @schemaname;
96 --PRINT @sql1;
97
98 SELECT TOP 1
99 @rownumber = rownumber
100 , @schemanameNEW = FOREIGNKEY_SchemaName
101 , @tablenameNEW = FOREIGNKEY_TableName
102 , @whereNEW = FOREIGNKEY_ColumnName + ' in (SELECT '+PARENT_ColumnName + @SQLTODelete + ')'
103 FROM @TMP
104 --SELECT count(*) as n FROM @TMP;
105 DELETE FROM @TMP WHERE rownumber=@rownumber;
106 --SELECT count(*) as n FROM @TMP;
107
108 --PRINT @rownumber;
109 --print @schemaname
110 --print @tablename
111 --print @where
112 IF (@tablename = @tablenameNEW)
113 exec sDBACascateDelete @schemanameNEW, @tablenameNEW, @whereNEW, 0
114 else
115 exec sDBACascateDelete @schemanameNEW, @tablenameNEW, @whereNEW, 1
116
117 -- DELETE FROM #TMP WHERE FOREIGNKEY_TableName = @tablename AND FOREIGNKEY_SchemaName = @schemaname;
118 IF (@n=0) break;
119 SET @n = @n - 1;
120END
121
122PRINT @sql
123
124END
125GO
Ideal use :
1
2exec sDBACascateDelete @schemaname='dbo', @tablename='Region', @where='EmployeesID < @EmployeesID'
3
4/** RESULT **/
5
6DELETE FROM [dbo].[EmployeeTerritories] WHERE TerritoryID in (SELECT TerritoryID FROM [dbo].[Territories] WHERE RegionID in (SELECT RegionID FROM [dbo].[Region] WHERE EmployeesID < @EmployeesID));
7DELETE FROM [dbo].[Territories] WHERE RegionID in (SELECT RegionID FROM [dbo].[Region] WHERE EmployeesID < @EmployeesID);
8DELETE FROM [dbo].[Region] WHERE EmployeesID < @EmployeesID;
This example the table dbo.[Employees] has a self-reference. In this case the code should be rewritten because it certainly will not work.
1
2exec sDBACascateDelete @schemaname='dbo', @tablename='Employees', @where='EmployeesID < @EmployeesID'
3
4/* RESULT */
5DELETE FROM [dbo].[Employees] WHERE ReportsTo in (SELECT EmployeeID FROM [dbo].[Employees] WHERE EmployeesID < @EmployeesID);
6DELETE FROM [dbo].[EmployeeTerritories] WHERE EmployeeID in (SELECT EmployeeID FROM [dbo].[Employees] WHERE EmployeesID < @EmployeesID);
7DELETE FROM [dbo].[Order Details] WHERE OrderID in (SELECT OrderID FROM [dbo].[Orders] WHERE EmployeeID in (SELECT EmployeeID FROM [dbo].[Employees] WHERE EmployeesID < @EmployeesID));
8DELETE FROM [dbo].[Orders] WHERE EmployeeID in (SELECT EmployeeID FROM [dbo].[Employees] WHERE EmployeesID < @EmployeesID);
9DELETE FROM [dbo].[Employees] WHERE EmployeesID < @EmployeesID;
** I use NorthWind database **
Comments