I was trying to build a script that would drop all foreign keys in a particular schema (I'm working on creating a new database which will need to be scripted to several other locations, a test environment and a production one). The easiest way to have these three separate environments is to work with my "CREATE" script on "development", and then stage that through our other environments at a later date. This requires (as one possible solution) that the beginning of the "CREATE" script is a sort of If Exists(...) DROP...
.
I have solved the problem I was having, but was hoping that someone could explain the behavior I was seeing (see below).
This code works (I get a statement that has all records as their own SQL statements):
DECLARE @SQL VARCHAR(MAX) = ''
DECLARE @Schema VARCHAR(100) = 'SchemaName'
SELECT
@SQL = @SQL
+ 'ALTER TABLE ' + tpa.name + CHAR(13) + CHAR(10)
+ CHAR(9) + 'DROP CONSTRAINT ' + fk.name +';' + CHAR(13) + CHAR(10)
FROM
sys.foreign_keys AS fk
JOIN sys.foreign_key_columns AS fkc
ON fkc.constraint_object_id = fk.object_id
JOIN sys.tables AS tpa
ON fk.parent_object_id = tpa.object_id
JOIN sys.columns AS cpa
ON tpa.object_id = cpa.object_id AND
fkc.parent_column_id = cpa.column_id
JOIN sys.tables AS tref
ON fkc.parent_object_id = tref.object_id
JOIN sys.columns AS cref
ON tref.object_id = cref.object_id AND
fkc.referenced_column_id = cref.column_id
WHERE
SCHEMA_NAME(fk.schema_id) = @Schema
PRINT @SQL
This code doesn't work (it only returns the last line of the recordset):
DECLARE @SQL VARCHAR(MAX) = ''
DECLARE @Schema VARCHAR(100) = 'SchemaName'
SELECT
@SQL = @SQL
+ 'ALTER TABLE ' + tpa.name + CHAR(13) + CHAR(10)
+ CHAR(9) + 'DROP CONSTRAINT ' + fk.name +';' + CHAR(13) + CHAR(10)
FROM
sys.foreign_keys AS fk
JOIN sys.foreign_key_columns AS fkc
ON fkc.constraint_object_id = fk.object_id
JOIN sys.tables AS tpa
ON fk.parent_object_id = tpa.object_id
JOIN sys.columns AS cpa
ON tpa.object_id = cpa.object_id AND
fkc.parent_column_id = cpa.column_id
JOIN sys.tables AS tref
ON fkc.parent_object_id = tref.object_id
JOIN sys.columns AS cref
ON tref.object_id = cref.object_id AND
fkc.referenced_column_id = cref.column_id
WHERE
SCHEMA_NAME(fk.schema_id) = @Schema
ORDER BY
OBJECT_NAME(fk.parent_object_id)
,OBJECT_NAME(fk.referenced_object_id)
,fk.name
PRINT @SQL
The offending line seems to be the OBJECT_NAME(fk.referenced_object_id)
in the ORDER BY
as commenting that out resolves the issue, but I don't understand why it's failing. My suspicion is that something is doing a group by inherently or something.
Even including all columns from the ORDER BY
doesn't seem to help:
DECLARE @SQL VARCHAR(MAX) = ''
DECLARE @Schema VARCHAR(100) = 'UserMgmt'
SELECT
@SQL = @SQL
+ 'ALTER TABLE ' + tpa.name + CHAR(13) + CHAR(10)
+ CHAR(9) + 'DROP CONSTRAINT ' + fk.name +';' + CHAR(13) + CHAR(10)
+ '--' + OBJECT_NAME(fk.referenced_object_id) + ', ' + OBJECT_NAME(fk.parent_object_id) + CHAR(13) + CHAR(10)
FROM
sys.foreign_keys AS fk
JOIN sys.foreign_key_columns AS fkc
ON fkc.constraint_object_id = fk.object_id
JOIN sys.tables AS tpa
ON fk.parent_object_id = tpa.object_id
JOIN sys.columns AS cpa
ON tpa.object_id = cpa.object_id AND
fkc.parent_column_id = cpa.column_id
JOIN sys.tables AS tref
ON fkc.parent_object_id = tref.object_id
JOIN sys.columns AS cref
ON tref.object_id = cref.object_id AND
fkc.referenced_column_id = cref.column_id
WHERE
SCHEMA_NAME(fk.schema_id) = @Schema
ORDER BY
OBJECT_NAME(fk.parent_object_id)
,OBJECT_NAME(fk.referenced_object_id)
,fk.name
PRINT @SQL
However, changing the JOIN
statement for the referenced table does make this work:
DECLARE @SQL VARCHAR(MAX) = ''
DECLARE @Schema VARCHAR(100) = 'UserMgmt'
SELECT
@SQL = @SQL
+ 'ALTER TABLE ' + tpa.name + CHAR(13) + CHAR(10)
+ CHAR(9) + 'DROP CONSTRAINT ' + fk.name +';' + CHAR(13) + CHAR(10)
+ '--' + OBJECT_NAME(fk.referenced_object_id) + ', ' + OBJECT_NAME(fk.parent_object_id) + CHAR(13) + CHAR(10)
FROM
sys.foreign_keys AS fk
JOIN sys.foreign_key_columns AS fkc
ON fkc.constraint_object_id = fk.object_id
JOIN sys.tables AS tpa
ON fk.parent_object_id = tpa.object_id
JOIN sys.columns AS cpa
ON tpa.object_id = cpa.object_id AND
fkc.parent_column_id = cpa.column_id
JOIN sys.tables AS tref
ON fk.referenced_object_id = tref.object_id
JOIN sys.columns AS cref
ON tref.object_id = cref.object_id AND
fkc.referenced_column_id = cref.column_id
WHERE
SCHEMA_NAME(fk.schema_id) = @Schema
ORDER BY
OBJECT_NAME(fk.parent_object_id)
,OBJECT_NAME(fk.referenced_object_id)
,fk.name
PRINT @SQL
Can anyone explain this behavior?