0

I need to create a stored procedure that:

  1. Accepts a table name as a parameter
  2. Find its dependencies (FKs)
  3. Removes them
  4. Truncate the table

I created the following so far based on http://www.mssqltips.com/sqlservertip/1376/disable-enable-drop-and-recreate-sql-server-foreign-keys/ . My problem is that the following script successfully does 1 and 2 and generates queries to alter tables but does not actually execute them. In another word how can execute the resulting "Alter Table ..." queries to actually remove FKs?

CREATE PROCEDURE DropDependencies(@TableName VARCHAR(50))
AS
BEGIN
SELECT 'ALTER TABLE ' + OBJECT_SCHEMA_NAME(parent_object_id) + '.[' + OBJECT_NAME(parent_object_id) + '] DROP CONSTRAINT ' + name
FROM sys.foreign_keys WHERE referenced_object_id=object_id(@TableName)
END



EXEC DropDependencies 'TableName'

Any idea is appreciated!

Update: I added the cursor to the SP but I still get and error: "Msg 203, Level 16, State 2, Procedure DropRestoreDependencies, Line 75 The name 'ALTER TABLE [dbo].[ChildTable] DROP CONSTRAINT [FK__ChileTable__ParentTable__745C7C5D]' is not a valid identifier."

Here is the updated SP: CREATE PROCEDURE DropRestoreDependencies(@schemaName sysname, @tableName sysname) AS BEGIN SET NOCOUNT ON

DECLARE @operation VARCHAR(10)  


SET @operation = 'DROP' --ENABLE, DISABLE, DROP  


DECLARE @cmd NVARCHAR(1000) 

DECLARE   
   @FK_NAME sysname,  
   @FK_OBJECTID INT,  
   @FK_DISABLED INT,  
   @FK_NOT_FOR_REPLICATION INT,  
   @DELETE_RULE    smallint,     
   @UPDATE_RULE    smallint,     
   @FKTABLE_NAME sysname,  
   @FKTABLE_OWNER sysname,  
   @PKTABLE_NAME sysname,  
   @PKTABLE_OWNER sysname,  
   @FKCOLUMN_NAME sysname,  
   @PKCOLUMN_NAME sysname,  
   @CONSTRAINT_COLID INT  


DECLARE cursor_fkeys CURSOR FOR   
   SELECT  Fk.name,  
           Fk.OBJECT_ID,   
           Fk.is_disabled,   
           Fk.is_not_for_replication,   
           Fk.delete_referential_action,   
           Fk.update_referential_action,   
           OBJECT_NAME(Fk.parent_object_id) AS Fk_table_name,   
           schema_name(Fk.schema_id) AS Fk_table_schema,   
           TbR.name AS Pk_table_name,   
           schema_name(TbR.schema_id) Pk_table_schema  
   FROM    sys.foreign_keys Fk LEFT OUTER JOIN   
           sys.tables TbR ON TbR.OBJECT_ID = Fk.referenced_object_id --inner join   
   WHERE   TbR.name = @tableName  
           AND schema_name(TbR.schema_id) = @schemaName  

OPEN cursor_fkeys  

FETCH NEXT FROM   cursor_fkeys   
   INTO @FK_NAME,@FK_OBJECTID,  
       @FK_DISABLED,  
       @FK_NOT_FOR_REPLICATION,  
       @DELETE_RULE,     
       @UPDATE_RULE,     
       @FKTABLE_NAME,  
       @FKTABLE_OWNER,  
       @PKTABLE_NAME,  
       @PKTABLE_OWNER  

WHILE @@FETCH_STATUS = 0   
BEGIN   

   -- create statement for dropping FK and also for recreating FK  
   IF @operation = 'DROP'  
   BEGIN  

       -- drop statement  
       SET @cmd = 'ALTER TABLE [' + @FKTABLE_OWNER + '].[' + @FKTABLE_NAME   
       + ']  DROP CONSTRAINT [' + @FK_NAME + ']'     

      EXEC @cmd  

       -- create process  
       DECLARE @FKCOLUMNS VARCHAR(1000), @PKCOLUMNS VARCHAR(1000), @COUNTER INT  

       -- create cursor to get FK columns  
       DECLARE cursor_fkeyCols CURSOR FOR   
       SELECT  COL_NAME(Fk.parent_object_id, Fk_Cl.parent_column_id) AS Fk_col_name,   
               COL_NAME(Fk.referenced_object_id, Fk_Cl.referenced_column_id) AS Pk_col_name  
       FROM    sys.foreign_keys Fk LEFT OUTER JOIN   
               sys.tables TbR ON TbR.OBJECT_ID = Fk.referenced_object_id INNER JOIN   
               sys.foreign_key_columns Fk_Cl ON Fk_Cl.constraint_object_id = Fk.OBJECT_ID   
       WHERE   TbR.name = @tableName  
               AND schema_name(TbR.schema_id) = @schemaName  
               AND Fk_Cl.constraint_object_id = @FK_OBJECTID -- added 6/12/2008  
       ORDER BY Fk_Cl.constraint_column_id  

       OPEN cursor_fkeyCols  

       FETCH NEXT FROM    cursor_fkeyCols INTO @FKCOLUMN_NAME,@PKCOLUMN_NAME  

       SET @COUNTER = 1  
       SET @FKCOLUMNS = ''  
       SET @PKCOLUMNS = ''  

       WHILE @@FETCH_STATUS = 0   
       BEGIN   

           IF @COUNTER > 1   
           BEGIN  
               SET @FKCOLUMNS = @FKCOLUMNS + ','  
               SET @PKCOLUMNS = @PKCOLUMNS + ','  
           END  

           SET @FKCOLUMNS = @FKCOLUMNS + '[' + @FKCOLUMN_NAME + ']'  
           SET @PKCOLUMNS = @PKCOLUMNS + '[' + @PKCOLUMN_NAME + ']'  

           SET @COUNTER = @COUNTER + 1  

           FETCH NEXT FROM    cursor_fkeyCols INTO @FKCOLUMN_NAME,@PKCOLUMN_NAME  
       END  

       CLOSE cursor_fkeyCols   
       DEALLOCATE cursor_fkeyCols   



   END  

   FETCH NEXT FROM    cursor_fkeys   
      INTO @FK_NAME,@FK_OBJECTID,  
           @FK_DISABLED,  
           @FK_NOT_FOR_REPLICATION,  
           @DELETE_RULE,     
           @UPDATE_RULE,     
           @FKTABLE_NAME,  
           @FKTABLE_OWNER,  
           @PKTABLE_NAME,  
           @PKTABLE_OWNER  
END  

CLOSE cursor_fkeys   
DEALLOCATE cursor_fkeys 
END

For running use:

EXEC DropRestoreDependencies dbo, ParentTable
6
  • 1
    Use a cursor to go through your SELECT results, populating a variable with the single column, and executing that query with EXEC(@YourVariable) Commented Aug 19, 2014 at 15:11
  • Thanks for the reply! I use cursor but I still an error. I updated my question with the new stored procedure.
    – Nicole
    Commented Aug 19, 2014 at 16:38
  • Put a "PRINT @cmd" statement on the line before the "EXEC @cmd" statement and look at what command it is attempting to execute when it triggers the error. Commented Aug 19, 2014 at 16:46
  • @Tab Alleman I did and ran the resulted queries separably. They work without any problems.
    – Nicole
    Commented Aug 19, 2014 at 17:04
  • 1
    Oh, you need to use parens with EXEC. So change it to "EXEC (@cmd)" Commented Aug 19, 2014 at 17:09

3 Answers 3

1

Use a cursor to go through your SELECT results, populating a variable with the single column, and executing that query with EXEC(@YourVariable). Be sure to use parens around the variable!

0
1

The issue is that you are only preparing the SQL statement and not executing it (I think)

CREATE PROCEDURE DropDependencies(@TableName VARCHAR(50))
AS
BEGIN
DECLARE @SQL nvarchar(max)
SELECT @SQL = 'ALTER TABLE ' + OBJECT_SCHEMA_NAME(parent_object_id) + '.[' + OBJECT_NAME(parent_object_id) + '] DROP CONSTRAINT ' + name
FROM sys.foreign_keys WHERE referenced_object_id=object_id(@TableName)
EXEC @SQL
END


EXEC DropDependencies 'TableName'

Whenever using EXEC though from constructed strings, ensure you aren't vulnerable to SQL Injection attacks.

5
  • Thanks for the answer! Now The problem is only one result is assigned to the @SQL. In some cases I have more than one dependencies!
    – Nicole
    Commented Aug 19, 2014 at 15:29
  • @nicole Ah, I follow. May need to set up a cursor and run through for each result. Cursors are evil, however, so there may be a better way
    – franglais
    Commented Aug 19, 2014 at 15:33
  • I already used the cursor but I get the error that "ALTER TABLE [dbo].[TableName] DROP CONSTRAINT ...' is not a valid identifier."
    – Nicole
    Commented Aug 19, 2014 at 15:36
  • @nicole you'll need to create the cursor in the sp created and execute the sql for each constraint found?
    – franglais
    Commented Aug 19, 2014 at 15:39
  • Yes! (It is not in the question as it is too long but I used the code in mssqltips.com/sqlservertip/1376/… and changed it to a stored procedure. when I change print to exec in the drop section, I get the error that I mentioned!
    – Nicole
    Commented Aug 19, 2014 at 15:52
0

Try Out SP_ExecuteSQL or Exec. I see that you are using Exec. Perhaps SP_ExecuteSQL will work?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.