How to Grant Execute All Functions In SQL Server to group - sql

I have a list of function I need to grant execute to specific group, I found that the query should be executed like this
GRANT EXECUTE ON [dbo].[FunctionName] TO [GroupName]
But since I have 40 functions in the database, so I need to execute it 40 times with updateing the finction name. And when I haave new unctions I need to execute the new one the same way, my question if there is a Script/Function that get all the functions name in the database and execute all just once. I am able to get the list of functions with this code:
SELECT name AS function_name
FROM sys.objects
WHERE type_desc LIKE '%FUNCTION%'
and also I create a function to execute it:
ALTER function [dbo].[listFunction]()
returns int
AS
BEGIN
declare #Result int;
declare #ListFn nvarchar(100);
set #ListFn = (
SELECT name AS function_name
FROM sys.objects
WHERE type_desc LIKE '%FUNCTION%'
);
if #ListFn=null
set #Result = 1
else
set #Result = 0
return #Result
end
but what is missing how to iterate each function and grant execute, so any help?
Edit: I have edited the query with this using the chema
DECLARE #SchemaName varchar(max)
DECLARE #GroupName varchar(max)
SET #SchemaName = 'dbo'
SET #GroupName = '[groupname]'
select 'GRANT EXECUTE ON OBJECT::' + #SchemaName + '.' + P.name + ' to ' + #GroupName
from sys.objects P
inner join sys.schemas S on P.schema_id = S.schema_id
where S.name = #SchemaName
and P.type_desc LIKE '%FUNCTION%'
Edit 2: I craete a procedure to execute the grant, because it cnnot work with function, so I executed it and no execeptionsshown, but I don't knwo if it i right or not:
CREATE PROCEDURE ExecuteAllFunctions
AS
BEGIN
DECLARE #i int
declare #Result int;
declare #ListFn nvarchar(100);
DECLARE #a TABLE (fnct nvarchar(max))
DECLARE #SchemaName varchar(max)
--DECLARE #a TABLE (id uniqueidentifier)
DECLARE #GroupName varchar(max)
SET #SchemaName = 'dbo'
SET #GroupName = '[GroupName]'
INSERT INTO #a select 'GRANT EXECUTE ON OBJECT::' + #SchemaName + '.' + P.name + ' to ' + #GroupName
from sys.objects P
inner join sys.schemas S on P.schema_id = S.schema_id
where S.name = #SchemaName
and P.type_desc LIKE '%FUNCTION%'
--EXEC #ListFn
--SET #i = 1
--WHILE (#i <= (SELECT MAX(fnct) FROM #a))
-- BEGIN
-- set #ListFn = (select fnct from #a a where a.fnct=)
-- SET #i = #i + 1
-- END
--if #ListFn=null
--set #Result = 1
--else
--set #Result = 0
--return #Result
end

Related

Get list of column names containing specific value SQL-Hue

I have 50 tables and I want to get list of all column names containing specific value in the column.
Something like: if 'Test' in column give me the column name. And I want to apply it for all 50 tables
Tables names are: abc1,abc2,abc3, … abcn.
There must be a better way to do this, but I did come across a query like this from a colleague a couple of years ago and I found the below (or a script similar to below that i may have tweaked before sending onto him) somewhere online (I imagine here on SO, but can't see to find where - I will update with link to original source if i can find it).
I would also just point out that this is a very heavy proc so I would take a backup of your db and restore it to a dev or test environment before executing it. Or even execute it against a test db that you might have in your localdb. The script searches all columns of all tables in a selected db for a string.
Personally I would probably export the data from each table to txt or csv and do a Find within them.
CREATE PROCEDURE FindMyData_String
#DataToFind NVARCHAR(4000),
#ExactMatch BIT = 0
AS
SET NOCOUNT ON
DECLARE #Temp TABLE(RowId INT IDENTITY(1,1), SchemaName sysname, TableName sysname, ColumnName SysName, DataType VARCHAR(100), DataFound BIT)
INSERT INTO #Temp(TableName,SchemaName, ColumnName, DataType)
SELECT C.Table_Name,C.TABLE_SCHEMA, C.Column_Name, C.Data_Type
FROM Information_Schema.Columns AS C
INNER Join Information_Schema.Tables AS T
ON C.Table_Name = T.Table_Name
AND C.TABLE_SCHEMA = T.TABLE_SCHEMA
WHERE Table_Type = 'Base Table'
And Data_Type In ('ntext','text','nvarchar','nchar','varchar','char')
DECLARE #i INT
DECLARE #MAX INT
DECLARE #TableName sysname
DECLARE #ColumnName sysname
DECLARE #SchemaName sysname
DECLARE #SQL NVARCHAR(4000)
DECLARE #PARAMETERS NVARCHAR(4000)
DECLARE #DataExists BIT
DECLARE #SQLTemplate NVARCHAR(4000)
SELECT #SQLTemplate = CASE WHEN #ExactMatch = 1
THEN 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
= ''' + #DataToFind + '''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
ELSE 'If Exists(Select *
From ReplaceTableName
Where Convert(nVarChar(4000), [ReplaceColumnName])
Like ''%' + #DataToFind + '%''
)
Set #DataExists = 1
Else
Set #DataExists = 0'
END,
#PARAMETERS = '#DataExists Bit OUTPUT',
#i = 1
SELECT #i = 1, #MAX = MAX(RowId)
FROM #Temp
WHILE #i <= #MAX
BEGIN
SELECT #SQL = REPLACE(REPLACE(#SQLTemplate, 'ReplaceTableName', QUOTENAME(SchemaName) + '.' + QUOTENAME(TableName)), 'ReplaceColumnName', ColumnName)
FROM #Temp
WHERE RowId = #i
PRINT #SQL
EXEC SP_EXECUTESQL #SQL, #PARAMETERS, #DataExists = #DataExists OUTPUT
IF #DataExists =1
UPDATE #Temp SET DataFound = 1 WHERE RowId = #i
SET #i = #i + 1
END
SELECT SchemaName,TableName, ColumnName
FROM #Temp
WHERE DataFound = 1
GO

Using values from Select Statement in a String for a Stored Procedure - MS SQL Server

I am writing a drop Procedure in SQL Server, but have hit a problem, in order to drop an index you must pass the table name in. I have wrote a piece of code to find the table (which works)
set #sqlndex = N'select name from sys.objects where object_id = (select object_id from sys.indexes where name = ''' + #objectname + ''')';
But I cant seem to take the returned value and use it, the code below is the full Procedure part I am working on:
What it should do:
It should print the table name (Testing reason / debugging)
It should then pass the name of the table to the drop string (+#result+)
if #objecttype='index' begin
IF EXISTS (SELECT * FROM sysindexes WHERE name = #objectname)
set #sqlndex = N'select name from sys.objects where object_id = (select object_id from sys.indexes where name = ''' + #objectname + ''')';
execute sp_executesql #sqlndex, #result = #result OUTPUT;
SELECT #result;
print #result;
set #SQL = 'DROP ' + #objecttype + ' [dbo].['+#result+'].['+#objectname+']';
select #SQL;
EXEC (#SQL);
end
Variables I am declaring
DECLARE #sql VARCHAR(MAX);
DECLARE #sqlndex NVARCHAR(MAX);
DECLARE #resultOUT NVARCHAR(MAX);
DECLARE #result NVARCHAR(MAX);
DECLARE #objecttype VARCHAR(MAX);
DECLARE #objectname VARCHAR(MAX);
Any help would be great
Try this:
Instead of
set #sqlndex = N'select name from sys.objects
where object_id = (select object_id from sys.indexes
where name = ''' + #objectname + ''')';
Write:
declare #result nvarchar(100)
declare #paramdef nvarchar(100)
set #sqlndex = N'select #resultout = name from sys.objects
where object_id = (select object_id from sys.indexes
where name = ''' + #objectname + ''')';
set #paramdef = N'#resultout nvarchar(100) output';
execute sp_executesql #sqlndex, #paramdef, #resultout = #result OUTPUT;
So you'll be able to manage #result value

While Loop to Iterate through Databases

I was wondering if someone could help me with creating a while loop to iterate through several databases to obtain data from one table from two columns. this is was I have done so far. nothing works because i do not know how to make the select statement work through each database with regards to the table that I am querying from each database (dbo.tbldoc)
DECLARE #Loop int
DECLARE #DBName varchar(300)
DECLARE #SQL varchar(max)
DECLARE #tableName VARCHAR(255)
SET #Loop = 1
SET #DBName = ''
WHILE #Loop = 1
BEGIN
SELECT [name] FROM sys.databases
WHERE [name] like 'z%' and create_date between '2010-10-17' and '2011-01-15'
ORDER BY [name]
SET #Loop = ##ROWCOUNT
IF #Loop = 0
BREAK
SET #SQL = ('USE ['+ #DBNAME +']')
IF EXISTS(SELECT [name] FROM sys.tables WHERE name != 'dbo.tbldoc' )
BEGIN
SELECT SUM(PGCOUNT), CREATED FROM **dbo.tbldoc**
END
ELSE
--BEGIN
PRINT 'ErrorLog'
END
I would consider sp_MSForEachDB which is a lot easier...
Edit:
EXEC sp_MSForEachDB 'USE [?]; IF DB_NAME() LIKE ''Z%%''
BEGIN
END
'
CREATE TABLE #T
(dbname sysname NOT NULL PRIMARY KEY,
SumPGCOUNT INT,
CREATED DATETIME)
DECLARE #Script NVARCHAR(MAX) = ''
SELECT #Script = #Script + '
USE ' + QUOTENAME(name) + '
IF EXISTS(SELECT * FROM sys.tables WHERE OBJECT_ID=OBJECT_ID(''dbo.tbldoc''))
INSERT INTO #T
SELECT db_name() AS dbname, SUM(PGCOUNT) AS SumPGCOUNT, CREATED
FROM dbo.tbldoc
GROUP BY CREATED;
'
FROM sys.databases
WHERE state=0 AND user_access=0 and has_dbaccess(name) = 1
AND [name] like 'z%' and create_date between '2010-10-17' and '2011-01-15'
ORDER BY [name]
IF (##ROWCOUNT > 0)
BEGIN
--PRINT #Script
EXEC (#Script)
SELECT * FROM #T
END
DROP TABLE #T
My code to search for data from more than one database would be:
use [master]
go
if object_id('tempdb.dbo.#database') is not null
drop TABLE #database
go
create TABLE #database(id INT identity primary key, name sysname)
go
set nocount on
insert into #database(name)
select name
from sys.databases
where name like '%tgsdb%' --CHANGE HERE THE FILTERING RULE FOR YOUR DATABASES!
and source_database_id is null
order by name
Select *
from #database
declare #id INT, #cnt INT, #sql NVARCHAR(max), #currentDb sysname;
select #id = 1, #cnt = max(id)
from #database
while #id <= #cnt
BEGIN
select #currentDb = name
from #database
where id = #id
set #sql = 'select Column1, Column2 from ' + #currentDb + '.dbo.Table1'
print #sql
exec (#sql);
print '--------------------------------------------------------------------------'
set #id = #id + 1;
END
go
DECLARE #Loop int
DECLARE #MaxLoop int
DECLARE #DBName varchar(300)
DECLARE #SQL varchar(max)
SET #Loop = 1
SET #DBName = ''
set nocount on
SET #MaxLoop = (select count([name]) FROM sys.databases where [name] like 'Z%')
WHILE #Loop <= #MaxLoop
BEGIN
SET #DBName = (select TableWithRowsNumbers.name from (select ROW_NUMBER() OVER (ORDER by [name]) as Row,[name] FROM sys.databases where [name] like 'Z%' ) TableWithRowsNumbers where Row = #Loop)
SET #SQL = 'USE [' + #DBName + ']'
exec (#SQL)
...
...
set #Loop = #Loop + 1
END
***Note: I didn't add the check if exists here.
I ended up writing one last week on the fly for some stuff I was doing.
Blog post here:
http://tsells.wordpress.com/2012/02/14/sql-server-database-iterator/
Here is the code.
SET NOCOUNT ON
GO
use master
go
Declare
#dbname nvarchar(500),
#variable1 int,
#variable2 int,
#variable3 int,
#totaldb int = 0,
#totaldbonserver int = 0,
#totaldbwithmatches int = 0
-- Get non system databases
Declare mycursor CURSOR for select name, database_id from SYS.databases where database_id > 4 order by name desc
open mycursor
fetch next from mycursor into #dbname, #variable1
while (##FETCH_STATUS <> -1)
BEGIN
DECLARE #ParmDefinition NVARCHAR(500)
Declare #mysql nvarchar(500) = 'select #variable2OUT = COUNT(*) from [' + #dbname + '].INFORMATION_SCHEMA.TABLES where Upper(TABLE_NAME) like ''MyTable''';
SET #ParmDefinition = N'#variable2OUT int OUTPUT'
set #totaldbonserver = #totaldbonserver + 1
Execute sp_executesql #mysql, #ParmDefinition, #variable2 OUTPUT
if #variable2 = 1
BEGIN
DECLARE #ParmDefinition2 NVARCHAR(500)
Declare #mysql2 nvarchar(500) = 'select #variable2OUT = COUNT(*) from [' + #dbname + '].dbo.MyTable';
SET #ParmDefinition2 = N'#variable2OUT int OUTPUT'
Execute sp_executesql #mysql2, #ParmDefinition2, #variable3 OUTPUT
set #totaldb = #totaldb + 1
if #variable3 > 1
BEGIN
Print #dbname + ' matched the criteria'
set #totaldbwithmatches = #totaldbwithmatches + 1
END
ELSE
Select 1
END
fetch next from mycursor into #dbname, #variable1
END
PRINT 'Total databases on server: '
Print #totaldbonserver
PRINT 'Total databases tested () : '
Print #totaldb
PRINT 'Total databases with matches: '
Print #totaldbwithmatches
CLOSE mycursor
DEALLOCATE mycursor
This doesn't use a loop. Hope this helps!
Note that "TABLE_OWNER" is that same as "SCHEMA Owner" and "TABLE_TYPE" will identify if the item is a table OR view.
--This will return all tables, table owners and table types for all database(s) that are NOT 'Offline'
--Offline database information will not appear
Declare #temp_table table(
DB_NAME varchar(max),
TABLE_OWNER varchar(max),
TABLE_NAME varchar(max),
TABLE_TYPE varchar(max),
REMARKS varchar(max)
)
INSERT INTO #temp_table (DB_NAME, TABLE_OWNER, TABLE_NAME, TABLE_TYPE,REMARKS)
EXECUTE master.sys.sp_MSforeachdb 'USE [?]; EXEC sp_tables'
SELECT DB_NAME, TABLE_OWNER, TABLE_NAME, TABLE_TYPE
FROM #temp_table
--Uncomment below if you are seaching for 1 database
--WHERE DB_NAME = '<Enter specific DB Name>'
--For all databases other than 'System Databases'
WHERE DB_NAME not in ('master','model','msdn','tempdb')
order by 1,2,3
You don't have to use a "USE DATABASE" statement. You can select from the particular database table by using a 3 part identifier as in:
select * from MyDatabase.dbo.MyTable

How to Check all stored procedure is ok in sql server?

How to check all stored procedure is ok in sql server if I drop a table or fields?
I found Cade's answer useful in formulating my own script for checking objects in a database, so I thought I'd share my script as well:
DECLARE #Name nvarchar(1000);
DECLARE #Sql nvarchar(1000);
DECLARE #Result int;
DECLARE ObjectCursor CURSOR FAST_FORWARD FOR
SELECT QUOTENAME(SCHEMA_NAME(o.schema_id)) + '.' + QUOTENAME(OBJECT_NAME(o.object_id))
FROM sys.objects o
WHERE type_desc IN (
'SQL_STORED_PROCEDURE',
'SQL_TRIGGER',
'SQL_SCALAR_FUNCTION',
'SQL_TABLE_VALUED_FUNCTION',
'SQL_INLINE_TABLE_VALUED_FUNCTION',
'VIEW')
--include the following if you have schema bound objects since they are not supported
AND ISNULL(OBJECTPROPERTY(o.object_id, 'IsSchemaBound'), 0) = 0
;
OPEN ObjectCursor;
FETCH NEXT FROM ObjectCursor INTO #Name;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Sql = N'EXEC sp_refreshsqlmodule ''' + #Name + '''';
--PRINT #Sql;
BEGIN TRY
EXEC #Result = sp_executesql #Sql;
IF #Result <> 0 RAISERROR('Failed', 16, 1);
END TRY
BEGIN CATCH
PRINT 'The module ''' + #Name + ''' does not compile.';
IF ##TRANCOUNT > 0 ROLLBACK TRANSACTION;
END CATCH
FETCH NEXT FROM ObjectCursor INTO #Name;
END
CLOSE ObjectCursor;
DEALLOCATE ObjectCursor;
It won't catch everything (dynamic SQL or latebound objects), but it can be useful - call sp_refreshsqlmodule on all non-schema bound stored procedures (you can call it before to ensure that dependencies are updated and then query the dependencies, or call it afterwards and see if anything is broken):
DECLARE #template AS varchar(max)
SET #template = 'PRINT ''{OBJECT_NAME}''
EXEC sp_refreshsqlmodule ''{OBJECT_NAME}''
'
DECLARE #sql AS varchar(max)
SELECT #sql = ISNULL(#sql, '') + REPLACE(#template, '{OBJECT_NAME}',
QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME))
FROM INFORMATION_SCHEMA.ROUTINES
WHERE OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME)),
N'IsSchemaBound') IS NULL
OR OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME)),
N'IsSchemaBound') = 0
EXEC (
#sql
)
In addition to the script from Michael Petito you can check for issues with late-bound objects in SPs (deferred name resolution) like this:
-- Based on comment from http://blogs.msdn.com/b/askjay/archive/2012/07/22/finding-missing-dependencies.aspx
-- Check also http://technet.microsoft.com/en-us/library/bb677315(v=sql.110).aspx
select o.type, o.name, ed.referenced_entity_name, ed.is_caller_dependent
from sys.sql_expression_dependencies ed
join sys.objects o on ed.referencing_id = o.object_id
where ed.referenced_id is null
I basically did the same thing, but wrote it to be CURSORless which is super fast.
DECLARE #Name nvarchar(1000);
DECLARE #Sql nvarchar(1000);
DECLARE #Result int;
DECLARE #Objects TABLE (
Id INT IDENTITY(1,1),
Name nvarchar(1000)
)
INSERT INTO #Objects
SELECT QUOTENAME(SCHEMA_NAME(o.schema_id)) + '.' + QUOTENAME(OBJECT_NAME(o.object_id))
FROM sys.objects o
WHERE type_desc IN (
'SQL_STORED_PROCEDURE',
'SQL_TRIGGER',
'SQL_SCALAR_FUNCTION',
'SQL_TABLE_VALUED_FUNCTION',
'SQL_INLINE_TABLE_VALUED_FUNCTION',
'VIEW')
--include the following if you have schema bound objects since they are not supported
AND ISNULL(OBJECTPROPERTY(o.object_id, 'IsSchemaBound'), 0) = 0
DECLARE #x INT
DECLARE #xMax INT
SELECT #xMax = MAX(Id) FROM #Objects
SET #x = 1
WHILE #x < #xMax
BEGIN
SELECT #Name = Name FROM #Objects WHERE Id = #x
SET #Sql = N'EXEC sp_refreshsqlmodule ''' + #Name + '''';
--PRINT #Sql;
BEGIN TRY
EXEC #Result = sp_executesql #Sql;
IF #Result <> 0 RAISERROR('Failed', 16, 1);
END TRY
BEGIN CATCH
PRINT 'The module ''' + #Name + ''' does not compile.';
IF ##TRANCOUNT > 0 ROLLBACK TRANSACTION;
END CATCH
SET #x = #x + 1
END
Couple of ways that come to mind
Most obvious way run the procedures
check dependencies on the table before you drop the table or a field. then check out those dependent proceudres
generate scripts on all procedures and search for that field or table
Query sysobjects
Once I made change to a table such as column rename, I have to alter all the stored procedures, functions and views that refer the table column. Obviously I have to manually alter them one by one. But my database contains hundreds of objects like these. So I wanted to make sure I have altered all the depending objects. One solution is to recompile all the objects (via a script). But recompilation happens on each object’s next execution only. But what I want is to validate them and get the details now.
For that I can use “sp_refreshsqlmodule” instead of “sp_recompile”. This will refresh each object and throws an error if its not parsing correctly.
Here is the script below;
-- table variable to store procedure names
DECLARE #tblObjects TABLE (ObjectID INT IDENTITY(1,1), ObjectName
sysname)
-- get the list of stored procedures, functions and views
INSERT INTO #tblObjects(ObjectName)
SELECT '[' + sc.[name] + '].[' + obj.name + ']'
FROM sys.objects obj
INNER JOIN sys.schemas sc ON sc.schema_id = obj.schema_id
WHERE obj.[type] IN ('P', 'FN', 'V') -- procedures, functions, views
-- counter variables
DECLARE #Count INT, #Total INT
SELECT #Count = 1
SELECT #Total = COUNT(*) FROM #tblObjects
DECLARE #ObjectName sysname
-- start the loop
WHILE #Count <= #Total BEGIN
SELECT #ObjectName = ObjectName
FROM #tblObjects
WHERE ObjectID = #Count
PRINT 'Refreshing... ' + #ObjectName
BEGIN TRY
-- refresh the stored procedure
EXEC sp_refreshsqlmodule #ObjectName
END TRY
BEGIN CATCH
PRINT 'Validation failed for : ' + #ObjectName + ', Error:' +
ERROR_MESSAGE() + CHAR(13)
END CATCH
SET #Count = #Count + 1
END
If any object throws an error I can now attend to it and manually fix the issue with it.
None of the answers given can find the error resulting from renaming or dropping a table
but be happy, I have a solution on SQL Server 2017 and higher versions:
DECLARE #NumberRecords INT
DECLARE #RowCount INT
DECLARE #Name NVARCHAR(MAX)
DECLARE #Command NVARCHAR(MAX)
DECLARE #Result int
DECLARE #Names TABLE (
[RowId] INT NOT NULL IDENTITY(1, 1),
[Name] NVARCHAR(MAX),
[Type] NVARCHAR(MAX)
)
INSERT INTO #Names
SELECT
QUOTENAME(SCHEMA_NAME([Objects].schema_id)) + '.' + QUOTENAME(OBJECT_NAME([Objects].object_id)) [Name],
type_desc [Type]
FROM sys.objects [Objects]
WHERE type_desc IN ('SQL_STORED_PROCEDURE',
'SQL_TRIGGER',
'SQL_SCALAR_FUNCTION',
'SQL_TABLE_VALUED_FUNCTION',
'SQL_INLINE_TABLE_VALUED_FUNCTION',
'VIEW')
ORDER BY [Name]
SET #RowCount = 1
SET #NumberRecords = (SELECT COUNT(*) FROM #Names)
WHILE (#RowCount <= #NumberRecords)
BEGIN
SELECT #Name = [Name]
FROM #Names
WHERE [RowId] = #RowCount
SET #Command = N'EXEC sp_refreshsqlmodule ''' + #Name + ''''
BEGIN TRY
EXEC #Result = sp_executesql #Command
IF #Result <> 0
BEGIN
RAISERROR('Failed', 16, 1)
END
ELSE
BEGIN
IF (NOT EXISTS (SELECT *
FROM sys.dm_sql_referenced_entities(#Name, 'OBJECT')
WHERE [is_incomplete] = 1))
BEGIN
DELETE
FROM #Names
WHERE [RowId] = #RowCount
END
END
END TRY
BEGIN CATCH
-- Nothing
END CATCH
SET #RowCount = #RowCount + 1
END
SELECT [Name],
[Type]
FROM #Names
I tried "Cade Roux" Answer , it went wrong and I fixed it as following
SELECT 'BEGIN TRAN T1;' UNION
SELECT REPLACE('BEGIN TRY
EXEC sp_refreshsqlmodule ''{OBJECT_NAME}''
END TRY
BEGIN CATCH
PRINT ''{OBJECT_NAME} IS INVALID.''
END CATCH', '{OBJECT_NAME}',
QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME))
FROM INFORMATION_SCHEMA.ROUTINES
WHERE OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME)),
N'IsSchemaBound') IS NULL
OR OBJECTPROPERTY(OBJECT_ID(QUOTENAME(ROUTINE_SCHEMA) + '.'
+ QUOTENAME(ROUTINE_NAME)),
N'IsSchemaBound') = 0
UNION
SELECT 'ROLLBACK TRAN T1;'
Same idea, but more universal - you check all user defined objects with bodies
And it shows you error during compiling. This is really useful after renaming/removing objects/columns etc
Just run it after database schema update to make sure that all body objects still valid
DECLARE #obj_name AS sysname, #obj_type AS sysname
DECLARE obj_cursor CURSOR FOR
SELECT SCHEMA_NAME(o.schema_id) + '.' + o.name, o.type_desc
FROM sys.objects o
INNER JOIN sys.sql_modules m ON o.object_id = m.object_id
WHERE o.is_ms_shipped = 0 AND m.is_schema_bound = 0
ORDER BY o.type_desc, SCHEMA_NAME(o.schema_id), o.name
OPEN obj_cursor
FETCH NEXT FROM obj_cursor INTO #obj_name, #obj_type
WHILE (##FETCH_STATUS <> -1)
BEGIN
BEGIN TRY
EXEC sp_refreshsqlmodule #obj_name
--PRINT 'Refreshing ''' + #obj_name + ''' completed'
END TRY
BEGIN CATCH
PRINT 'ERROR - ' + #obj_type + ' ''' + #obj_name + ''':' + ERROR_MESSAGE()
END CATCH
FETCH NEXT FROM obj_cursor INTO #obj_name, #obj_type
END
CLOSE obj_cursor
DEALLOCATE obj_cursor
My approach was a little bit different. I've created alter script for a bunch of procs in SSMS and then waited for few seconds so SSMS process them and Ive got what I wanted:
O then SSMS right border a red dot for any line in error, which I can easily check, correct and later execute same script to update with correct values.

How to rebuild view in SQL Server 2008

There is a view in my DB that someone defined with a * from one table. I just added a new column to that table and I want the view to reflect the new column. Besides re-executing the view creation script, is there another way to rebuild the view? I am looking for something similar to how sp_recompile will recompile a stored procedure (or more accurately flag it to be compiled next time it is called).
Update: On a long shot I tried calling sp_recompile on the view and while the call worked, it didn't rebuild the view.
Update 2: I would like to be able to do this from a script. So the script that adds the columns to the table could also update the view. So like I said, something similar to sp_recompile.
I believe what you're looking for is
sp_refreshview [ #viewname = ] 'viewname'
Updates the metadata for the specified
non-schema-bound view. Persistent
metadata for a view can become
outdated because of changes to the
underlying objects upon which the view
depends.
See Microsoft Docs
In order to rebuild all views of a SQL Server database, you could use the following script:
DECLARE #view_name AS NVARCHAR(500);
DECLARE views_cursor CURSOR FOR
SELECT TABLE_SCHEMA + '.' +TABLE_NAME FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'VIEW'
AND OBJECTPROPERTY(OBJECT_ID(TABLE_NAME), 'IsMsShipped') = 0
ORDER BY TABLE_SCHEMA,TABLE_NAME
OPEN views_cursor
FETCH NEXT FROM views_cursor
INTO #view_name
WHILE (##FETCH_STATUS <> -1)
BEGIN
BEGIN TRY
EXEC sp_refreshview #view_name;
PRINT #view_name;
END TRY
BEGIN CATCH
PRINT 'Error during refreshing view "' + #view_name + '".';
END CATCH;
FETCH NEXT FROM views_cursor
INTO #view_name
END
CLOSE views_cursor;
DEALLOCATE views_cursor;
This is a slightly modified version from this blog posting. It uses the sp_refreshview stored procedure, too.
As well as Cory's answer, you could define it properly using schemabinding and the full column list.
CREATE VIEW MyView
WITH SCHEMABINDING
AS
SELECT
col1, col2, col3, ..., coln
FROM
MyTable
GO
Slightly modified script that refreshes all views, calls sp_recompile, sp_refresh and gets list from sys.views:
DECLARE #view_name AS NVARCHAR(500);
DECLARE views_cursor CURSOR FOR SELECT DISTINCT name from sys.views
OPEN views_cursor
FETCH NEXT FROM views_cursor
INTO #view_name
WHILE (##FETCH_STATUS <> -1)
BEGIN
BEGIN TRY
EXEC sp_recompile #view_name;
EXEC sp_refreshview #view_name;
PRINT #view_name;
END TRY
BEGIN CATCH
PRINT 'Error during refreshing view "' + #view_name + '".';
END CATCH;
FETCH NEXT FROM views_cursor
INTO #view_name
END
CLOSE views_cursor;
DEALLOCATE views_cursor;
sp_refreshview does not seem to be relyable! When I used the code from Uwe Keim/BogdanRB I got many errors even if the view has no invalid references! The following code did the trick for me (to determine which view is invalid after schema changes):
DECLARE #view_name AS NVARCHAR(500);
DECLARE #Query AS NVARCHAR(600);
SET #Query = '';
DECLARE views_cursor CURSOR FOR SELECT DISTINCT ('[' + SCHEMA_NAME(schema_id) + '].[' + name + ']') AS Name FROM sys.views
OPEN views_cursor
FETCH NEXT FROM views_cursor
INTO #view_name
WHILE (##FETCH_STATUS <> -1)
BEGIN
EXEC sp_recompile #view_name;
SELECT #Query = 'SELECT ''' + #view_name + ''' AS Name, COUNT(*) FROM ' + #view_name + ' AS Count; ';
EXEC (#Query);
-- PRINT #view_name;
FETCH NEXT FROM views_cursor
INTO #view_name
END
CLOSE views_cursor;
DEALLOCATE views_cursor;
Here is my favorite script for this (I modified an old sp_exec checking script I had), it uses EXEC sp_refreshsqlmodule #name
SET NOCOUNT ON;
-- Set ViewOnly to 1 to view missing EXECUTES. Set to 0 to correct missing EXECUTEs
DECLARE
#ViewOnly INT; SET #ViewOnly = 0;
-- Role to set execute permission on.
DECLARE
#ROLE sysname ; set #ROLE = QUOTENAME('spexec');
DECLARE
#ID INT,
#LAST_ID INT,
#NAME NVARCHAR(2000),
#SQL NVARCHAR(2000);
DECLARE #Permission TABLE (
id INT IDENTITY(1,1) NOT NULL,
spName NVARCHAR(2000),
object_type NVARCHAR(2000),
roleName NVARCHAR(2000),
permission NVARCHAR(2000),
state NVARCHAR(2000)
)
--Initialise the loop variable
SET #LAST_ID = 0
--Get all the stored procs into a temp table.
WHILE #LAST_ID IS NOT NULL
BEGIN
-- Get next lowest value
SELECT #ID = MIN(object_id)
FROM sys.objects
WHERE object_id > #LAST_ID
-- Looking for Stored Procs, Scalar, Table and Inline Functions
AND type IN ('P','FN','IF','TF','AF','FS','FT','PC', 'V')
SET #LAST_ID = #ID
IF #ID IS NOT NULL
BEGIN
INSERT INTO #Permission
SELECT o.name,
o.type_desc,
r.name,
p.permission_name,
p.state_desc
FROM sys.objects AS o
LEFT outer JOIN sys.database_permissions AS p
ON p.major_id = o.object_id
LEFT OUTER join sys.database_principals r
ON p.grantee_principal_id = r.principal_id
WHERE o.object_id = #ID
AND o.type IN ('P','FN','IF','TF','AF','FS','FT','PC', 'V')
--Exclude special stored procs, which start with dt_...
AND NOT o.name LIKE 'dt_%'
AND NOT o.name LIKE 'sp_%'
AND NOT o.name LIKE 'fn_%'
END
END
--GRANT the Permissions, only if the viewonly is off.
IF ISNULL(#ViewOnly,0) = 0
BEGIN
--Initialise the loop variable
SET #LAST_ID = 0
WHILE #LAST_ID IS NOT NULL
BEGIN
-- Get next lowest value
SELECT #ID = MIN(id)
FROM #Permission
WHERE roleName IS NULL
AND id > #LAST_ID
SET #LAST_ID = #ID
IF #ID IS NOT NULL
BEGIN
SELECT #NAME = spName
FROM #Permission
WHERE id = #ID
PRINT 'EXEC sp_refreshsqlmodule ' + #NAME
-- Build the DCL to do the GRANT
SET #SQL = 'sp_refreshsqlmodule [' + #NAME + ']'
-- Run the SQL Statement you just generated
EXEC (#SQL)
END
END
--Reselect the now changed permissions
SELECT o.name,
o.type_desc,
r.name,
p.permission_name,
p.state_desc
FROM sys.objects AS o
LEFT outer JOIN sys.database_permissions AS p
ON p.major_id = o.object_id
LEFT OUTER join sys.database_principals r
ON p.grantee_principal_id = r.principal_id
WHERE o.type IN ('P','FN','IF','TF','AF','FS','FT','PC', 'V')
AND NOT o.name LIKE 'dt_%'
AND NOT o.name LIKE 'sp_%'
AND NOT o.name LIKE 'fn_%'
ORDER BY o.name
END
ELSE
BEGIN
--ViewOnly: select the stored procs which need EXECUTE permission.
SELECT *
FROM #Permission
WHERE roleName IS NULL
END
Right-click on the view and choose Refresh from the popup menu?
You can use this sp:
CREATE PROCEDURE dbo.RefreshViews
#dbName nvarchar(100) = null
AS
BEGIN
SET NOCOUNT ON;
DECLARE #p nvarchar(250) = '#sql nvarchar(max) out'
DECLARE #q nvarchar(1000)
DECLARE #sql nvarchar(max)
if #dbName is null
select #dbName = DB_NAME()
SELECT #q = 'SELECT #sql = COALESCE(#sql + '' '', '''') + ''EXEC sp_refreshview ''''[' + #dbName + '].['' + TABLE_SCHEMA + ''].['' + TABLE_NAME + '']'''';''
FROM [' + #dbName + '].INFORMATION_SCHEMA.Views '
EXEC sp_executesql #q , #p ,#sql out
EXEC sp_executesql #sql
END
GO