I've been asked whether it's possible to create a stored procedure that will copy all views in the current database to another one (named via stored procedure parameter).
For context, all databases have the same schemas. This situation arises thanks to a 3rd party risk modelling tool that generates each run's output as an entirely new database (rather than additional rows in an existing database). The user wants an easy way to "apply" their 20 or so custom views (from their "Template" database) to another identical database on-demand. They wish to maintain the "latest version" of the views in one database, and then "Update" (Drop + Create) views on any other database by executing this stored procedure. As far as I can tell, this ask is almost identical to the ask in Copy a view definition from one database to another one in SQL Server, which never got an answer.
Where I've gotten so far:
Getting a view definition: Easy
SELECT @ViewDefinition = definition FROM sys.sql_modules WHERE [object_id] = OBJECT_ID('dbo.SampleView');The question at Copy a view definition from one database to another one in SQL Server even has code for iteratively getting the definitions of all views.
Passing in a database name as a parameter: Medium
Not knowing the target database name at script creation time is hard. As far as I know, this guarantees that you will be relying on Dynamic SQL (
EXEC) to do whatever you're doing.Creating a view on another database: Hard
You can't just add
USE [OtherDatabase]to the start of some dynamic CREATE VIEW statement - this yields the error "CREATE VIEW must be the first statement in a query batch.". And you can't just add aGOstatement in there either - the errorIncorrect syntax near ‘GO'serves as a reminder that this is not valid TSQL. A blog post I found solved the issue by invokingEXEC [SomeOtherDatabase].dbo.sp_executesql @CreateViewSQLBut unfortunately, this solution can't be used in the context where 'SomeOtherDatabase' is intended to be passed in as an argument.
This took me to an incredibly awkward situation of having to construct and execute a dynamic SQL statement from within another dynamic SQL statement.
So currently my proof-of-concept solution looks like this:
ALTER PROCEDURE [dbo].[usp_Enhance_Database_With_Views]
@TargetDatabase SYSNAME,
AS
IF DB_ID(@TargetDatabase) IS NULL /*Validate the database name exists*/
BEGIN
RAISERROR('Invalid Database Name passed',16,1)
RETURN
END
DECLARE @CreateViewStatement NVARCHAR(MAX) = '
DECLARE @ViewDefinition NVARCHAR(MAX);
SELECT @ViewDefinition = definition FROM sys.sql_modules
WHERE [object_id] = OBJECT_ID(''dbo.SampleView'');
EXEC ' + QUOTENAME(@TargetDatabase) + '.dbo.sp_executesql @ViewDefinition'
EXEC (@CreateViewStatement);
I couldn't find anything else like it online, but surprisingly (to me) it works. "SampleView" gets copied over to the new database. I can now expand on this concept to copy over all views. But before I go any further...
Have I missed the mark here? Is there a stored procedure solution that doesn't include building and executing dynamic SQL within another dynamic SQL?
