Scope of ## variable in TSQL - sql-server

In the following TSQL code I can use my local variable in first few lines and then I cannot use it again. Why am I not able to use it in the last line of my code ?
Where does its scope end?
DECLARE ##CurrentDB varchar(50);
SET ##CurrentDB = 'MyDBNAME';
-- Find Data & Log Fiel locations
SELECT DB_NAME(database_id) AS DatabaseName, name AS LogicalFileName, physical_name AS PhysicalFileName, size/(128*1024) [GB]
FROM sys.master_files AS mf
WHERE DB_NAME(database_id) = ##CurrentDB
-- Detach DB
USE
GO
ALTER DATABASE SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
USE [master]
GO
EXEC master.dbo.sp_detach_db #dbname = ##Cur
GO
Here is the error:

Any time you pass SQL Server a GO command, that ends the context in which the variable exists and it is no longer accessible by anything after that point in the T-SQL code. "Global" variables as such do not exist in SQL Server, but there are ways around it, generally by implementing a global variable table (either temporary or permanent).
You can get the general idea from this blog post that sets up a permanent table to track global variables.

As a workaround, you can use a Global Temp Table:
Declare #CurrentDB varchar(50)
SET #CurrentDB = 'MyDBNAME'
Create Table ##CurrentDB (Name varchar(50))
Insert Into ##CurrentDB Values (#CurrentDB)
GO
-- ...
GO
Declare #CurrentDB varchar(50)
Select Top 1 #CurrentDB = Name From ##CurrentDB
Select #CurrentDB
This should work even if you are using different databases in each part of your script.

Why use a global variable or temp table at all? This cries out to me to be a user defined stored procedure.
Here are the business rules.
1 - You basically want to get the location and size of a database you want to detach.
2 - Want to set database to single user mode.
3 - You want to detach the database. Just remember the files will be hanging around afterwards.
I created it in the MSDB database but you can put it in your own toolbox database.
I did not check to see if the database is really in use only mode. - TODO list
Just check the mode in the sys.databases table. If the ALTER, fails do not try the detach. Just notify the user to find the spids and kill them.
http://technet.microsoft.com/en-us/library/ms178534.aspx
4 - I did not put any error handling in. - TODO list
Last but not least, this solution could be prone to SQL injection, do not give the world access.
In short, the stored procedure below does just what you want.
--
-- Create a user stored procedure
--
-- Start in msdb
use msdb
go
-- drop existing
if object_id('my_detach_process') > 0
drop procedure my_detach_process
go
-- create new
create procedure my_detach_process(#dbname sysname)
as
-- Show the data
SELECT
DB_NAME(mf.database_id) AS DatabaseName,
mf.name AS LogicalName,
mf.physical_name AS PhysicalName, mf.size as SizeMb
FROM sys.master_files AS mf
WHERE DB_NAME(database_id) = #dbname;
-- Set to single user
DECLARE #sqlstmt1 nvarchar(512) = '';
SET #sqlstmt1 = 'ALTER DATABASE [' + #dbname + '] SET SINGLE_USER WITH ROLLBACK IMMEDIATE';
EXEC sp_executesql #sqlstmt1;
-- Detach
DECLARE #sqlstmt2 nvarchar(512) = '';
SET #sqlstmt2 = 'USE [master]; EXEC master.dbo.sp_detach_db #dbname = ' + #dbname;
EXEC sp_executesql #sqlstmt2;
GO
--
-- Sample call
--
-- Choose master
use master
go
-- Create toy db
create database toy;
go
-- Call the sp
exec msdb.dbo.my_detach_process #dbname = 'Toy'
Sample output from sample call.

Related

The specified schema name "sys" either does not exist or you do not have permission to use it

I needed Msforeach_table stored procedure which depends upon sys.MSforeach_worker (System) stored procedure.
I am following this source code to create stored procedure MSforeach_worker
The syntax here is for dbo and not for sys so I have changed it to sys.MSforeach_worker from dbo.MSforeach_worker
When I try to create in my Databases, i get this error
The specified schema name "sys" either does not exist or you do not
have permission to use it
And when I try to create it in master db, I get
CREATE PROCEDURE permission denied in database 'master'
I am confused where should I run this script to create System stored procedure in my SQL server.
I have googled but could not find solution to my problem.
First, don't use undocumented system stored procedures. These are not supported.
Second, if these undocumented procs don't already exist, you must be using Azure SQL Database. Azure SQL Database has a significantly different architecture with regards to separation of master and user databases. Rather than trying to port the procs, I suggest you create your own proc with the functionality you need. Below is an example.
CREATE PROC dbo.usp_ForEachTable
#SQL nvarchar(MAX)
AS
DECLARE
#SQLBatch nvarchar(MAX)
, #TableName nvarchar(261);
DECLARE tables CURSOR LOCAL FAST_FORWARD FOR
SELECT QUOTENAME(OBJECT_SCHEMA_NAME(object_id)) + '.' + QUOTENAME(name)
FROM sys.tables
WHERE is_ms_shipped = 0;
OPEN tables;
WHILE 1 = 1
BEGIN
FETCH NEXT FROM tables INTO #TableName;
IF ##FETCH_STATUS = -1 BREAK;
SET #SQLBatch = REPLACE(#SQL, N'?', #TableName);
EXEC sp_executesql #SQLBatch;
END;
CLOSE tables;
DEALLOCATE tables;
GO

How can I create an UPDATE statement from a large XML data type?

I am working with two databases that are not accessible at the same time. One of the standard methods of dealing with this I've seen on here is to create dynamic sql for loading one from the other.
I created a stored procedure that would drop update statements from an existing database. My issue is what happens when the XML is too large to be held in a VARCHAR(max).
Here is a relevant snippet from my attempt where field2 is actually of an XML data type:
DECLARE #field1Col VARCHAR(50)
DECLARE #field2Col VARCHAR(max)
DECLARE #vsSQL VARCHAR(max)
DECLARE curUpdates CURSOR FOR
-- field 1 is varchar(50), not null
-- field 2 is XML(.), null
SELECT
t.field1
,REPLACE(CAST(t.[field2] AS VARCHAR(max)), '''', '''''')
FROM
myTable t
WHERE
t.criteria = 0
OPEN curUpdates
FETCH NEXT FROM curUpdates INTO #field1Col, #field2Col
WHILE ##FETCH_STATUS = 0
BEGIN
SET #vsSQL = 'UPDATE dbo.myTable SET [field1] = ''' + #field1Col+ ''' WHERE [field2] = ''' + #field2Col + ''''
INSERT INTO #tmp ( SQLText ) VALUES ( #vsSQL )
FETCH NEXT FROM curUpdates INTO #field1Col, #field2Col
END
CLOSE curUpdates
DEALLOCATE curUpdates
SET NOCOUNT OFF;
SELECT * FROM #tmp
The issue I have is that even using VARCHAR(max), the XML will sometimes overrun the size. The end product just stops when it reaches the so many characters (the max size of a VARCHAR?).
Is there another approach for working with large XML (splitting into chunks, avoid casting, etc.) where I can build a string of update statements from it?
I do not have access to database B. I'd like to (one time run) update
a few tables in database B
The one time run could point to something like this:
CREATE DATABASE MyOneTimeRun;
GO
USE MyOneTimeRun;
GO
SELECT * INTO MyCopy FROM YourDatabase.dbo.YourTable;
GO
BACKUP DATABASE [MyOneTimeRun] TO DISK = N'C:\Path\MyOneTimeRun.bak' WITH NOFORMAT, NOINIT
,NAME = N'MyOneTimeRun-Copy of MyTable'
,SKIP, NOREWIND, NOUNLOAD, STATS = 10
GO
USE master;
GO
EXEC msdb.dbo.sp_delete_database_backuphistory #database_name = N'MyOneTimeRun'
GO
USE [master]
GO
ALTER DATABASE [MyOneTimeRun] SET SINGLE_USER WITH ROLLBACK IMMEDIATE
GO
USE [master]
GO
DROP DATABASE [MyOneTimeRun]
GO
Now you have a BAK-file with the content you need which you can restore on your other server.
There you use the appropriate scripts to shuffle your data typesafe and clean from the copy into your target.

Copy a view definition from one database to another one in SQL Server

I am developping a script that allows me to create all the views present in database1 in another database (database2).
I am trying to do that using a cursor that loop on all the views of database1 and then try to execute the definition of that view on the second database.
Unfortunately it doesn't work. I get the following error:
Syntaxe incorrecte vers 'go'.
Msg 111, Niveau 15, État 1, Ligne 14
'CREATE VIEW' doit être la première instruction d'un traitement de requêtes.
This is my code
declare #database2 varchar(50), #database1 varchar(50)
set #database2 = 'Local'
set #database1 = 'prod'
declare #Query nvarchar(max), #view_definition nvarchar(max), #count int
set #count = 0
declare curseur cursor for SELECT top 1 view_definition FROM prod.information_schema.VIEWS
open curseur
fetch curseur into #view_definition
While ##FETCH_STATUS = 0
Begin
set #count = #count + 1
--Print 'Vue N° ' + cast(#count as varchar) + ':'
set #Query = N'Use ' + #database2 +CHAR(13)+CHAR(10)+ 'go' + #view_definition +CHAR(13)+CHAR(10)+ 'go'
print #Query
exec sp_executesql #Query
fetch curseur into #view_definition
End
Close curseur
deallocate curseur
This code was executed from database1.
However when I execute the result of the 'print #Query' instruction, it works!!
Does anyone can help me to resolve the problem?
Thanks in advance
There are two things here:
You can't USE another database in a stored procedure, although is the other database is on the same server you can use CREATE VIEW databasename.schemaname.viewname (.... If it's on another server, yiu could try setting it up as a linked server and using servername.database.schema.viewname.
sp_executesql expects one statement, and doesn't accept GO to my
knowledge (which is what the error is telling you). You could try to
put in ';' instead (and you don't need the CHAR(13)'s if you do
although they make it easier to read).
In case this helps someone in the future, here's my solution to this problem. The full history of how I came up with it is over at Stored Procedure to Copy Views from Current Database to Another
CREATE PROCEDURE [dbo].[usp_Copy_View_To_Database]
#ViewName SYSNAME, -- The name of the view to copy over
#DatabaseName SYSNAME, -- The name of the database to copy the view to
#overwrite bit = 1 -- Whether to overwrite any existing view
AS
IF DB_ID(#DatabaseName) IS NULL -- Validate the database name exists
BEGIN
RAISERROR('Invalid Destination Database Name passed',16,1)
RETURN
END
SET NOCOUNT ON
IF #overwrite = 1 -- If set to overwrite, try to drop the remote view
BEGIN
DECLARE #DropViewStatement NVARCHAR(MAX) =
'EXEC ' + QUOTENAME(#DatabaseName) + '.sys.sp_executesql N''DROP VIEW IF EXISTS ' + QUOTENAME(#ViewName) + ';'';'
EXEC (#DropViewStatement);
END
-- Extract the saved definition of the view
DECLARE #ViewDefinition NVARCHAR(MAX);
SELECT #ViewDefinition = definition FROM sys.sql_modules WHERE [object_id] = OBJECT_ID(#ViewName);
-- Check for a mismatch between the internal view name and the expected name (TODO: Resolve this automatically?)
IF #ViewDefinition NOT LIKE ('%' + #ViewName + '%')
BEGIN
DECLARE #InternalName NVARCHAR(MAX) = SUBSTRING(#ViewDefinition, 3, CHARINDEX(char(10), #ViewDefinition, 3)-4);
PRINT ('Warning: The view named '+#ViewName+' has an internal definition name that is different ('+#InternalName+'). This may have been caused by renaming the view after it was created. You will have to drop and recreate it with the correct name.')
END
-- Substitute any hard-coded references to the current database with the destination database
SET #ViewDefinition = REPLACE(#ViewDefinition, db_name(), #DatabaseName);
-- Generate the dynamic SQL that will create the view on the remote database
DECLARE #CreateViewStatement NVARCHAR(MAX) =
'EXEC ' + QUOTENAME(#DatabaseName) + '.sys.sp_executesql N''' + REPLACE(#ViewDefinition,'''','''''') + ''';'
--PRINT '#CreateViewStatement: ' + #CreateViewStatement -- Can be used for debugging
-- Execute the create statement
EXEC (#CreateViewStatement);
In short, you need two layers of nested dynamic SQL:
Inner layer to execute the "CREATE VIEW" statement, which must be on its own. This is executed using EXEC SomeDatabase.sys.sp_executesql #CreateViewSQL
One more layer to dynamically specify "SomeDatabase" via a parameter (assuming you require the flexibility of copying it to a database not known at scripting time).
Calling the above stored proc in the inner-loop of the original poster's tentative solution should solve the problem of copying a view to another database.
Note that simply looping over all views might pose a challenge if views depend on one another. There may be some additional complexity involving resolving the dependency tree of views an copying them in the correct order. Alternatively, a "dumb and easy" approach might be to loop over all views, ignore failures, and keep repeating the process until all views have been created.

sys.database_principals is not executed in current database if called from sp procedure (stored in master)

I would like to print out database users of an actual database in a SP procedure (see the code of sp_PrintUsers below), however, for some reason it print out database users of master. It seems that it is a general behavior of SP procedure for all database-level views despite the fact that any database-level SQL statement is executed in the actual database. If we print out the DB_NAME that it is clearly not master, so what is wrong?
Is there any workaround?
use [master]
go
create procedure sp_PrintUsers
as
begin
SELECT DB_NAME() AS DataBaseName
select name from sys.database_principals;
end
go
use [actual_database]
go
exec sp_PrintUsers
Try executing the select dynamically as in:
EXEC('select name from sys.database_principals;');
If that does not help build the query to reference the catalog view with a three part name.
Try this :
use [master]
go
create procedure sp_PrintUsers
as
begin
declare #dbname varchar(30) = DB_NAME()
EXEC ('select name from ' + #dbname + '.sys.database_principals');
end
go
use [actual_database]
go
exec sp_PrintUsers

Syntax check all stored procedures?

i want to ensure that all stored procedures are still syntactically valid. (This can happen if someone renames/deletes a table/column).
Right now my solution to check the syntax of all stored procedures is to go into Enterprise Manager, select the first stored procedure in the list, and use the procedure:
Enter
Alt+C
Escape
Escape
Down Arrow
Goto 1
It works, but it's pretty tedious. i'd like a stored procedure called
SyntaxCheckAllStoredProcedures
like the other stored procedure i wrote that does the same thing for views:
RefreshAllViews
For everyone's benefit, RefreshAllViews:
RefreshAllViews.prc
CREATE PROCEDURE dbo.RefreshAllViews AS
-- This sp will refresh all views in the catalog.
-- It enumerates all views, and runs sp_refreshview for each of them
DECLARE abc CURSOR FOR
SELECT TABLE_NAME AS ViewName
FROM INFORMATION_SCHEMA.VIEWS
OPEN abc
DECLARE #ViewName varchar(128)
-- Build select string
DECLARE #SQLString nvarchar(2048)
FETCH NEXT FROM abc
INTO #ViewName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQLString = 'EXECUTE sp_RefreshView '+#ViewName
PRINT #SQLString
EXECUTE sp_ExecuteSQL #SQLString
FETCH NEXT FROM abc
INTO #ViewName
END
CLOSE abc
DEALLOCATE abc
For everyone's benefit, a stored procedure to mark all stored procedure as needing a recompile (marking a stored procedure for recompile will not tell you if it's syntactically valid):
RecompileAllStoredProcedures.prc
CREATE PROCEDURE dbo.RecompileAllStoredProcedures AS
DECLARE abc CURSOR FOR
SELECT ROUTINE_NAME
FROM INFORMATION_SCHEMA.routines
WHERE ROUTINE_TYPE = 'PROCEDURE'
OPEN abc
DECLARE #RoutineName varchar(128)
-- Build select string once
DECLARE #SQLString nvarchar(2048)
FETCH NEXT FROM abc
INTO #RoutineName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQLString = 'EXECUTE sp_recompile '+#RoutineName
PRINT #SQLString
EXECUTE sp_ExecuteSQL #SQLString
FETCH NEXT FROM abc
INTO #RoutineName
END
CLOSE abc
DEALLOCATE abc
For completeness sake, the UpdateAllStatistics procedure. This will update all statistics in the database by doing a full data scan:
RefreshAllStatistics.prc
CREATE PROCEDURE dbo.RefreshAllStatistics AS
EXECUTE sp_msForEachTable 'UPDATE STATISTICS ? WITH FULLSCAN'
You can also do this "in-place" - without getting all the create statements.
In addition to setting NOEXEC ON, you will also need to set your favorite SHOWPLAN_* ON (I use SHOWPLAN_TEXT). Now you can get rid of your step 2 and just execute each procedure you retrieved in step 1.
Here is a sample using an individual stored procedure. You can work it into your favorite loop:
create procedure tests #bob int as
select * from missing_table_or_view
go
set showplan_text on;
go
set noexec on
exec tests
set noexec off
go
set showplan_text off;
go
drop procedure tests
go
The above sample should generate the following output:
Msg 208, Level 16, State 1, Procedure tests, Line 2
Invalid object name 'missing_table_or_view'.
The check suggested by KenJ is definitely the best one, since the recreate/alter-approaches does not find all errors. E.g.
impossible execution plans due to query-hints
I even had an SP referencing a non-existing table that went through without the error being detected.
Please find my version that checks all existing SPs at once with KenJ's method below. AFAIK, it will detect every error that will keep the SP from being executed.
--Forces the creation of execution-plans for all sps.
--To achieve this, a temporary SP is created that calls all existing SPs.
--It seems like the simulation of the parameters is not necessary. That makes things a lot easier.
DECLARE #stmt NVARCHAR(MAX) = 'CREATE PROCEDURE pTempCompileTest AS ' + CHAR(13) + CHAR(10)
SELECT #stmt = #stmt + 'EXEC [' + schemas.name + '].[' + procedures.name + '];'
FROM sys.procedures
INNER JOIN sys.schemas ON schemas.schema_id = procedures.schema_id
WHERE schemas.name = 'dbo'
ORDER BY procedures.name
EXEC sp_executesql #stmt
GO
--Here, the real magic happens.
--In order to display as many errors as possible, XACT_ABORT is turned off.
--Unfortunately, for some errors, the execution stops anyway.
SET XACT_ABORT OFF
GO
--Showplan disables the actual execution, but forces t-sql to create execution-plans for every statement.
--This is the core of the whole thing!
SET SHOWPLAN_ALL ON
GO
--You cannot use dynamic SQL in here, since sp_executesql will not be executed, but only show the string passed in in the execution-plan
EXEC pTempCompileTest
GO
SET SHOWPLAN_ALL OFF
GO
SET XACT_ABORT ON
GO
--drop temp sp again
DROP PROCEDURE pTempCompileTest
--If you have any errors in the messages-window now, you should fix these...
If you are using sql 2008 r2 or below then do not use
SET NOEXEC ON
It only checks the syntax and not for potential errors like the existence of tables or columns.
Instead use:
SET FMTONLY ON
it will do a full compile as it tries to return the meta data of the stored procedure.
For 2012 and you will need to use stored procedure:
sp_describe_first_result_set
Also you can do a complete script in Tsql that checks all sp and views, its just a bit of work.
UPDATE
I wrote a complete solution for in tsql that goes through all user defined stored proceedures and checks there syntax. the script is long winded but can be found here http://chocosmith.wordpress.com/2012/12/07/tsql-recompile-all-views-and-stored-proceedures-and-check-for-error/
In addition you might want to consider using Visual Studio Team System 2008 Database Edition which, among other things, does a static verification of all stored procedures in the project on build, thus ensuring that all are consistent with the current schema.
I know this is way old, but I created a slightly different version that actually re-creates all stored procedures, thus throwing errors if they cannot compile. This is something you do not achieve by using the SP_Recompile command.
CREATE PROCEDURE dbo.UTL_ForceSPRecompilation
(
#Verbose BIT = 0
)
AS
BEGIN
--Forces all stored procedures to recompile, thereby checking syntax validity.
DECLARE #SQL NVARCHAR(MAX)
DECLARE #SPName NVARCHAR(255)
DECLARE abc CURSOR FOR
SELECT NAME, OBJECT_DEFINITION(o.[object_id])
FROM sys.objects AS o
WHERE o.[type] = 'P'
ORDER BY o.[name]
OPEN abc
FETCH NEXT FROM abc
INTO #SPName, #SQL
WHILE ##FETCH_STATUS = 0
BEGIN
--This changes "CREATE PROCEDURE" to "ALTER PROCEDURE"
SET #SQL = 'ALTER ' + RIGHT(#SQL, LEN(#SQL) - (CHARINDEX('CREATE', #SQL) + 6))
IF #Verbose <> 0 PRINT #SPName
EXEC(#SQL)
FETCH NEXT FROM abc
INTO #SPName, #SQL
END
CLOSE abc
DEALLOCATE abc
END
I know this is a old question but this is my solution when I could not find any suiting.
I required to validate my stored procedures and views after alot of changes in the database.
Basicly what i wanted was to try to do a ALTER PROCEDURE and ALTER VIEW using the current procedures and view (not actually changing them).
I have written this that works fairly well.
Note! Do not perform on live database, make a copy to validate and then fix the things need fixing. Also sys.sql_modules can be inconsistent so take extra care. I do not use this to actually make the changes, only to check which are not working properly.
DECLARE #scripts TABLE
(
Name NVARCHAR(MAX),
Command NVARCHAR(MAX),
[Type] NVARCHAR(1)
)
DECLARE #name NVARCHAR(MAX), -- Name of procedure or view
#command NVARCHAR(MAX), -- Command or part of command stored in syscomments
#type NVARCHAR(1) -- Procedure or view
INSERT INTO #scripts(Name, Command, [Type])
SELECT P.name, M.definition, 'P' FROM sys.procedures P
JOIN sys.sql_modules M ON P.object_id = M.object_id
INSERT INTO #scripts(Name, Command, [Type])
SELECT V.name, M.definition, 'V' FROM sys.views V
JOIN sys.sql_modules M ON V.object_id = M.object_id
DECLARE curs CURSOR FOR
SELECT Name, Command, [Type] FROM #scripts
OPEN curs
FETCH NEXT FROM curs
INTO #name, #command, #type
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRY
IF #type = 'P'
SET #command = REPLACE(#command, 'CREATE PROCEDURE', 'ALTER PROCEDURE')
ELSE
SET #command = REPLACE(#command, 'CREATE VIEW', 'ALTER VIEW')
EXEC sp_executesql #command
PRINT #name + ' - OK'
END TRY
BEGIN CATCH
PRINT #name + ' - FAILED: ' + CAST(ERROR_NUMBER() AS NVARCHAR(MAX)) + ' ' + ERROR_MESSAGE()
--PRINT #command
END CATCH
FETCH NEXT FROM curs
INTO #name, #command, #type
END
CLOSE curs
A bit of a drawn-out option:
Create a copy of the database
(backup and restore). You could do this on the target database, if your confidence level is high.
Use SSMS to script out all the
stored procedures into a single script file
DROP all the procedures
Run the script to recreate them. Any that can't be created will error out.
Couple of fussy gotchas in here, such as:
You want to have the "if proc exists
then drop proc GO create proc ... GO"
syntax to separte each procedure.
Nested procedures will fail if they
call a proc that has not yet been
(re)created. Running the script several
times should catch that (since
ordering them properly can be a real
pain).
Other and more obscure issues might crop up, so be wary.
To quickly drop 10 or 1000 procedures, run
SELECT 'DROP PROCEDURE ' + schema_name(schema_id) + '.' + name
from sys.procedures
select the output, and run it.
This assumes you're doing a very infrequent task. If you have to do this regularly (daily, weekly...), please let us know why!
There is no way to do it from T-SQL, or Enterprise Manager, so i had to write something from client code. i won't post all the code here, but the trick is to:
1) Get a list of all stored procedures
SELECT ROUTINE_NAME AS StoredProcedureName
FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_TYPE = 'PROCEDURE' --as opposed to a function
ORDER BY ROUTINE_NAME
2) Get the stored procedure create T-SQL:
select
c.text
from dbo.syscomments c
where c.id = object_id(N'StoredProcedureName')
order by c.number, c.colid
option(robust plan)
3) Run the create statement with NOEXEC on, so that the syntax is checked, but it doesn't actually try to create the stored procedure:
connection("SET NOEXEC ON", ExecuteNoRecords);
connection(StoredProcedureCreateSQL, ExecuteNoRecords);
connection("SET NOEXEC ON", ExecuteNoRecords);
Here is an amendment which deals with multiple schemas
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[RefreshAllViews] AS
-- This sp will refresh all views in the catalog.
-- It enumerates all views, and runs sp_refreshview for each of them
DECLARE abc CURSOR FOR
SELECT TABLE_SCHEMA+'.'+TABLE_NAME AS ViewName
FROM INFORMATION_SCHEMA.VIEWS
OPEN abc
DECLARE #ViewName varchar(128)
-- Build select string
DECLARE #SQLString nvarchar(2048)
FETCH NEXT FROM abc
INTO #ViewName
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQLString = 'EXECUTE sp_RefreshView ['+#ViewName+']'
PRINT #SQLString
EXECUTE sp_ExecuteSQL #SQLString
FETCH NEXT FROM abc
INTO #ViewName
END
CLOSE abc
DEALLOCATE abc
GO

Resources