SQL Server Copying stored procedures and changing database reference

zf2sa74q  于 2023-10-15  发布在  其他
关注(0)|答案(3)|浏览(159)

I have a stored procedure that copies all the stored procedures in one database to another, changing the database reference. However, it currently has to be run on the destination db, whereas I would prefer to run it on the source db. I'm unsure how to point the relevant statement to the correct db.

  1. -- Delete all procedures in TO database - must run on TO db
  2. DECLARE @procName varchar(500)
  3. DECLARE cur1 cursor FOR
  4. SELECT [name] FROM [DestDB].sys.objects WHERE type = 'p'
  5. OPEN cur1
  6. FETCH NEXT FROM cur1 INTO @procName
  7. WHILE @@fetch_status = 0
  8. BEGIN
  9. EXEC('drop procedure [' + @procName + ']') --Problem statement
  10. FETCH NEXT FROM cur1 INTO @procName
  11. END
  12. CLOSE cur1
  13. DEALLOCATE cur1
  14. -- Copy all procedures from FROM database
  15. DECLARE @sql NVARCHAR(MAX);
  16. DECLARE @Name NVARCHAR(32) = 'DestDB'; --TO database
  17. DECLARE cur2 CURSOR FOR
  18. SELECT Definition
  19. FROM [SourceDB].[sys].[procedures] p
  20. INNER JOIN [SourceDB].sys.sql_modules m ON p.object_id = m.object_id
  21. OPEN cur2
  22. FETCH NEXT FROM cur2 INTO @sql
  23. WHILE @@FETCH_STATUS = 0
  24. BEGIN
  25. SET @sql = REPLACE(@sql,'''','''''')
  26. SET @sql = 'USE [' + @Name + ']; EXEC(''' + @sql + ''')'
  27. EXEC(@sql)
  28. FETCH NEXT FROM cur2 INTO @sql
  29. END
  30. CLOSE cur2
  31. DEALLOCATE cur2

The problem is the 'drop procedure ' call. You can't specify the database in the call, so it operates on the active one. I need to be able to specify the database that the 'drop procedure' runs on, so I can run the procedure from the source db.

xqnpmsa8

xqnpmsa81#

Why do you not use a 'USE' statement before the drop, as you are doing later inside the CURSOR?

  1. EXEC('USE [' + @Name + ']; drop procedure [' + @procName + ']')

Simply DECLARE the @Name variable earlier. It should work assuming all the procs are in the same database. "CREATE OR ALTER" should also complete the task, as mentioned, if you're using SQL Server 2016 and above.

ux6nzvsh

ux6nzvsh2#

Rather than EXEC (<SQL>) syntax, which is advised against, use sys.sp_executesql . YOu could then either you could prefix with the procedure with relevant database, such as TestDB.sys.sp_executesql , or you could assign the procedure name to a variable, SET @ProcName = N'TestDB.sys.sp_executesql' and then use EXEC @ProcName .

When you execute a procedure, it runs in the context of that database, so DROP PROC YourProc would drop a procedure in the procedure in the other database.

Note that in the below, you get different database IDs:

  1. USE master;
  2. GO
  3. SELECT DB_ID();
  4. EXEC tempdb.sys.sp_executesql N'SELECT DB_ID();';
  5. DECLARE @ProcName nvarchar(500) = N'model.sys.sp_executesql';
  6. EXEC @ProcName N'SELECT DB_ID();';

So, DROP ing a procedure would loom like this:

  1. USE Sandbox; --Connect to a different database
  2. GO
  3. --Create sample proc
  4. CREATE PROC dbo.YourProc1 AS
  5. BEGIN
  6. SELECT 1 AS I;
  7. END;
  8. GO
  9. --Create another sample proc
  10. CREATE PROC dbo.YourProc2 AS
  11. BEGIN
  12. SELECT 1 AS I;
  13. END;
  14. GO
  15. --Switch database
  16. USE master;
  17. GO
  18. EXEC Sandbox.dbo.YourProc1; --Check it works
  19. EXEC Sandbox.dbo.YourProc2; --Check it works
  20. GO
  21. EXEC Sandbox.sys.sp_executesql N'DROP PROC dbo.YourProc1;'; --Drop using 3 part naming
  22. GO
  23. DECLARE @ProcName nvarchar(500) = N'Sandbox.sys.sp_executesql';
  24. EXEC @ProcName N'DROP PROC dbo.YourProc2;'; --Drop using variable
  25. GO
  26. EXEC Sandbox.dbo.YourProc1; --Fails
  27. GO
  28. EXEC Sandbox.dbo.YourProc2; --Fails
展开查看全部
tcbh2hod

tcbh2hod3#

For reference, this is what I wound up with:

  1. USE [DestDB]
  2. GO
  3. /****** Object: StoredProcedure [dbo].[USP_Update_1_DropAndCopy_Procs] Script Date: 10/9/2023 10:58:25 AM ******/
  4. SET ANSI_NULLS ON
  5. GO
  6. SET QUOTED_IDENTIFIER ON
  7. GO
  8. -- =================================================================================
  9. -- Author: Me
  10. -- Description: Copy stored procedures from source to destination
  11. -- Create date: 10/06/2023
  12. -- =================================================================================
  13. ALTER PROCEDURE [dbo].[USP_Update_1_DropAndCopy_Procs]
  14. @SourceServer varchar(50),
  15. @SourceDB varchar(50),
  16. @DestDB varchar(50)
  17. AS
  18. BEGIN
  19. SET NOCOUNT ON;
  20. DECLARE @sql NVARCHAR(MAX);
  21. -- Delete all procedures in DESTINATION database
  22. DECLARE @procName varchar(500)EXEC('DECLARE cur1 cursor FOR SELECT [name] FROM [' + @DestDB + '].[sys].[objects] WHERE type = ''p'' ')
  23. OPEN cur1
  24. FETCH NEXT FROM cur1 INTO @procName
  25. WHILE @@fetch_status = 0
  26. BEGIN
  27. EXEC('USE [' + @DestDB + ']; drop procedure [' + @procName + ']')
  28. FETCH NEXT FROM cur1 INTO @procName
  29. END
  30. CLOSE cur1
  31. DEALLOCATE cur1
  32. -- Copy all procedures from SOURCE database
  33. EXEC('DECLARE cur2 CURSOR FOR SELECT Definition FROM [' + @SourceServer + '].[' + @SourceDB + '].[sys].[procedures] p INNER JOIN [' + @SourceServer + '].[' + @SourceDB + '].sys.sql_modules m ON p.object_id = m.object_id')
  34. OPEN cur2
  35. FETCH NEXT FROM cur2 INTO @sql
  36. WHILE @@FETCH_STATUS = 0
  37. BEGIN
  38. SET @sql = REPLACE(@sql,'''','''''')
  39. SET @sql = 'USE [' + @DestDB + ']; EXEC(''' + @sql + ''')'
  40. EXEC(@sql)
  41. FETCH NEXT FROM cur2 INTO @sql
  42. END
  43. CLOSE cur2
  44. DEALLOCATE cur2
  45. END
展开查看全部

相关问题