Stored procedure to remove FK of a given table - sql

I need to create a stored procedure that:
Accepts a table name as a parameter
Find its dependencies (FKs)
Removes them
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

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!

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.

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

Related

Stored procedure to drop the column in SQL Server

I created many tables and I have noticed that I have created one useless column in all the tables. I want to create a stored procedure which will drop one specific column and can be useful in all the column.
I created this stored procedure but I'm getting an error. Help me please
You cannot parametrize table and column names with parameters - those are only valid for values - not for object names.
If this is a one-time operation, the simplest option would be to generate the ALTER TABLE ... DROP COLUMN ... statements in SSMS using this code:
SELECT
'ALTER TABLE ' + SCHEMA_NAME(t.schema_id) + '.' + t.Name +
' DROP COLUMN Phone;'
FROM
sys.tables t
and then execute this code in SSMS; the output from it is a list of statement which you can then copy & paste to a new SSMS window and execute.
If you really want to do this as a stored procedure, you can apply the same basic idea - and then just use code (a cursor) to iterate over the commands being generated, and executing them - something like this:
CREATE PROCEDURE dbo.DropColumnFromAllTables (#ColumnName NVARCHAR(100))
AS
BEGIN
DECLARE #SchemaName sysname, #TableName sysname
-- define cursor over all tables which contain this column in question
DECLARE DropCursor CURSOR LOCAL FAST_FORWARD
FOR
SELECT
SchemaName = s.Name,
TableName = t.Name
FROM
sys.tables t
INNER JOIN
sys.schemas s ON t.schema_id = s.schema_id
WHERE
EXISTS (SELECT * FROM sys.columns c
WHERE c.object_id = t.object_id
AND c.Name = #ColumnName);
-- open cursor and start iterating over the tables found
OPEN DropCursor
FETCH NEXT FROM DropCursor INTO #SchemaName, #TableName
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #Stmt NVARCHAR(1000)
-- generate the SQL statement
SET #Stmt = N'ALTER TABLE [' + #SchemaName + '].[' + #TableName + '] DROP COLUMN [' + #ColumnName + ']';
-- execute that SQL statement
EXEC sp_executeSql #Stmt
FETCH NEXT FROM DropCursor INTO #SchemaName, #TableName
END
CLOSE DropCursor
DEALLOCATE DropCursor
END
This procedure should work.
It loops through all cols and then deletes the column where sum(col) is zero.
Take a Backup of the Table
alter procedure deletecolumnsifzero #tablename varchar(1000)
as
set nocount on
declare #n int
declare #sql nvarchar(1000)
declare #sum_cols nvarchar(1000)
declare #c_id nvarchar(100)
set #n = 0
declare c1 cursor for
select column_name from information_schema.columns
where
table_name like #tablename
--Cursor Starts
open c1
fetch next from c1
into #c_id
while ##fetch_status = 0
begin
set #sql=''
set #sql='select #sum_cols = sum('+#c_id+') from ['+#tablename+']'
exec sp_Executesql #sql,N'#sum_cols int out,#tablename nvarchar(100)',#sum_cols out,#tablename
if(#sum_cols = 0)
begin
set #n=#n+1
set #sql=''
set #sql= #sql+'alter table ['+#tablename+'] drop column ['+#c_id+']'
exec sp_executesql #sql
end
fetch next from c1
into #c_id
end
close c1
deallocate c1

Incorrect syntax SQL

Why do I get this error when I try to execute the following code?
I have a table NewTable1 with two columns: column1 and column2.
I get this error: Incorrect syntax near 'column2'.
--DROP COLUMN PROCEDURE
CREATE PROCEDURE DropColumn
#tableName varchar(50),
#columnName varchar(50)
AS
BEGIN
DECLARE #SQL nvarchar(500);
SET #SQL = N'ALTER TABLE ' + QUOTENAME(#tableName)
+ ' DROP COLUMN ' + QUOTENAME(#columnName);
EXEC sp_executesql #SQL;
END
RETURN 0
GO
USE SKI_SHOP;
EXEC DropColumn 'NewTable1', 'column2';
GO
Use appropriate data types. Also You will only be able to drop Columns for tables in callers default schema. Since procedure doesn't take schema into consideration, therefore you can only pass the table name and if a table exists in other than caller default schema they wont be able to delete it using this procedure .
CREATE PROCEDURE DropColumn
#tableName SYSNAME,
#columnName SYSNAME
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = N' ALTER TABLE ' + QUOTENAME(#tableName)
+ N' DROP COLUMN ' + QUOTENAME(#columnName);
EXEC sp_executesql #SQL;
END
GO
I over looked some basic simple issues in my first approach, whenever creating of Dropping objects in SQL Server always check if they exist, to avoid any errors . A more complete and safe approach would be something like ...
This time I have also added schema as a parameter.
ALTER PROCEDURE DropColumn
#tableName SYSNAME,
#columnName SYSNAME,
#Schema SYSNAME,
#Success BIT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX);
SET #SQL = N' IF EXISTS (SELECT * FROM sys.tables t
INNER JOIN sys.columns c
ON t.[object_id] = c.[object_id]
INNER JOIN sys.schemas sc
ON t.[schema_id] = sc.[schema_id]
WHERE t.name = #tableName
AND c.name = #columnName
AND sc.name = #Schema)
BEGIN
ALTER TABLE ' + QUOTENAME(#Schema)+ '.' + QUOTENAME(#tableName)
+ N' DROP COLUMN ' + QUOTENAME(#columnName)
+ N' SET #Success = 1; '
+ N' END
ELSE
BEGIN
SET #Success = 0;
END '
EXEC sp_executesql #SQL
,N'#tableName SYSNAME, #columnName SYSNAME, #Schema SYSNAME, #Success BIT OUTPUT'
,#tableName
,#columnName
,#Schema
,#Success OUTPUT
END
GO

Best Way To Convert All "SMALLINT" Columns Within A Database Schema To "BIT"? (SQL)

How do I convert all smallint type columns from my database to bit types?
I am using SQL Server 2008.
In SQL Server you can do it with ALTER TABLE my_table ALTER COLUMN my_column [new_datatype].
Be careful of things like default values because I haven't tested with them.
Example 1 - will give a list of queries for you to review / amend / execute (safer option).
DECLARE #TableSchema VARCHAR(100)
DECLARE #TableName VARCHAR(100)
DECLARE #ColumnName VARCHAR(100)
DECLARE #Query NVARCHAR(1000)
DECLARE #FromDataType NVARCHAR(50)
DECLARE #ToDataType NVARCHAR(50)
SET #TableSchema = 'dbo';
SET #FromDataType = 'smallint';
SET #ToDataType = 'bit';
DECLARE c CURSOR FAST_FORWARD FOR
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = #TableSchema
AND TABLE_NAME <> 'sysdiagrams'
AND DATA_TYPE = #FromDataType
OPEN c;
FETCH NEXT FROM c INTO #TableName, #ColumnName;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Query = N'ALTER TABLE ' + #TableName + N' ALTER COLUMN ' + #ColumnName + N' ' + #ToDataType -- + CHAR(13) + N'GO'
PRINT #Query
EXEC sp_EXECUTESQL #Query
FETCH NEXT FROM c INTO #TableName, #ColumnName;
END
CLOSE c;
DEALLOCATE c;
Example 2 - will execute (recommend running example 1 first!)
DECLARE #TableSchema VARCHAR(100)
DECLARE #TableName VARCHAR(100)
DECLARE #ColumnName VARCHAR(100)
DECLARE #Query NVARCHAR(1000)
DECLARE #FromDataType NVARCHAR(50)
DECLARE #ToDataType NVARCHAR(50)
SET #TableSchema = 'dbo';
SET #FromDataType = 'smallint';
SET #ToDataType = 'bit';
DECLARE c CURSOR FAST_FORWARD FOR
SELECT TABLE_NAME, COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = #TableSchema
AND TABLE_NAME <> 'sysdiagrams'
AND DATA_TYPE = #FromDataType
OPEN c;
FETCH NEXT FROM c INTO #TableName, #ColumnName;
WHILE ##FETCH_STATUS = 0
BEGIN
SET #Query = N'ALTER TABLE ' + #TableName + N' ALTER COLUMN ' + #ColumnName + N' ' + #ToDataType + CHAR(13) + N' GO'
PRINT #Query
FETCH NEXT FROM c INTO #TableName, #ColumnName;
END
CLOSE c;
DEALLOCATE c;
Please be careful doing this and test it on a backup database first. The following query will create ALTER statements for each column in your database that have SMALLINT datatype to convert them to BIT.
select 'ALTER TABLE ' + QUOTENAME(o.Name) + ' ALTER COLUMN ' + QUOTENAME(c.Name) + ' BIT' as Command
from sys.objects o
inner join sys.columns c
on o.object_id = c.object_id
where system_type_id = 52
and o.Type = 'U'
Also, be sure each column listed only contains 1 or 0 or you will get truncation errors when you run the script.
If you are asking about converting the column data type, I don't thing you can do that directly. You can add a new column as BIT and populate it from the old column, then drop the old column and rename the new one back to the old name.
See the online docs for more info.

Dropping a table with all its dependencies (Microsoft SQL Server)

How can I drop a table with all its dependencies [SPs, Views, etc.] (Microsoft SQL Server) without knowing its dependencies upfront? I know I can display all dependencies in Mangement Studio but I'm searching for utility script that I could simply speficy an object and it would drop this object with all its dependencies.
The best thing to do it is "Generate scripts for Drop"
Select Database -> Right Click -> Tasks -> Generate Scripts - will open wizard for generating scripts
Select the database -> next
Set option 'Script to create' to true (want to create)
Set option 'Script to Drop' to true (want to drop)
Set option 'Generate script for dependent object' to true -> Next
Select the Check box to select objects wish to create script
Select the choice to write script (File, New window, Clipboard)
Execute the script
This way we can customize our script i.e., we can do scripting for selected objects of a database.
I hope this will help you!
Best Wishes, JP
You can use Sp_Depends to find the dependencies. With that you can modify the script from this answer Maybe someone less lazy than me will do that for you.
Note: Each object of course could have its own dependencies so you'll need to process them as well.
Delete a SQL object using its schema-qualified name. For tables, the constraints are dropped first.
Errors are ignored.
create procedure [dbo].[spDropObject] (#fullname nvarchar(520))
as
begin
begin try
declare #type nvarchar(5)
declare #resolvedFullname nvarchar(520)
declare #resolvedName nvarchar(255)
set #type = null
set #resolvedFullname = null
set #resolvedName = null
--find the object
select
#type = o.[type]
,#resolvedFullname = '[' + object_schema_name(o.id) + '].[' + o.[name] + ']'
,#resolvedName = '[' + o.[name] + ']'
from dbo.sysobjects o
where id = object_id(#fullname)
--PROCEDURE
if(#type = 'P')
begin
exec('drop procedure ' + #resolvedFullname);
return;
end
--VIEW
if(#type = 'V')
begin
exec('drop view ' + #resolvedFullname);
return;
end
--FUNCTION
if(#type = 'FN' or #type = 'TF')
begin
exec('drop function ' + #resolvedFullname);
return;
end
--TRIGGER
if(#type = 'TF')
begin
exec('drop trigger ' + #resolvedFullname);
return;
end
--CONSTRAINT
if(#type = 'C' or #type = 'UQ' or #type = 'D' or #type = 'F' or #type = 'PK' or #type = 'K')
begin
declare #fullTablename nvarchar(520);
set #fullTablename = null
--find the contraint's table
select #fullTablename ='[' + object_schema_name(t.[object_id]) + '].[' + t.[Name] + ']'
from sys.tables t
join sys.schemas s on t.schema_id = s.schema_id
where t.object_id = (select parent_obj from dbo.sysobjects where id = object_id(#resolvedFullname))
exec('alter table ' + #fullTablename + ' drop constraint ' + #resolvedName);
return;
end
--TABLE (drop all constraints then drop the table)
if(#type = 'U')
begin
--find FK references to the table
declare #fktab table([Name] nvarchar(255))
insert #fktab
select
[Name] = '[' + object_name(fkc.[constraint_object_id]) + ']'
/*
,[Parent] = '[' + object_schema_name(fkc.[parent_object_id]) + '].[' + object_name(fkc.[parent_object_id]) + ']'
,[Ref] = '[' + object_schema_name(fkc.[referenced_object_id]) + '].[' + object_name(fkc.[referenced_object_id]) + ']'
*/
from sys.foreign_key_columns as fkc
where referenced_object_id = object_id(#resolvedFullname)
order by [Name]
--iterate FKs
while(1=1)
begin
declare #constraint nvarchar(255)
set #constraint = null
select top 1
#constraint = [Name]
from #fktab
if(#constraint is not null)
begin
--drop FK constraint
exec [dbo].[spDropObject] #constraint;
delete from #fktab where [Name] = #constraint --remove current record from working table
end
else break;
end
--find constraints for table
declare #constraintTab table ([Name] nvarchar(255));
insert #constraintTab
select [name]
from sys.objects
where parent_object_id = object_id(#resolvedFullname)
order by [name]
--iterate constraints
while(1=1)
begin
set #constraint = null;
select top 1 #constraint = [Name] from #constraintTab
if(#constraint is not null)
begin
--drop constraint
exec [dbo].[spDropObject] #constraint;
delete from #constraintTab where [Name] = #constraint --remove current record from working table
end
else break;
end
--drop table
exec('drop table ' + #resolvedFullname);
return;
end
end try
begin catch
declare #message nvarchar(max)
set #message = error_message( ) ;
print #message
end catch
end
In my case, I specifically wanted to drop a specified table and the tables that depend on that table. It wasn't useful to me to only drop the foreign key constraints that reference it. I wrote a stored procedure to do this
CREATE PROCEDURE DropDependentTables (
#tableName NVARCHAR(64))
AS
-- Find and drop all tables that depend on #tableName
WHILE EXISTS(SELECT *
FROM sys.foreign_keys
WHERE OBJECT_NAME(referenced_object_id) = #tableName AND
OBJECT_NAME(parent_object_id) != #tableName)
BEGIN
DECLARE #dependentTableName NVARCHAR(64)
SELECT TOP 1 #dependentTableName = OBJECT_NAME(parent_object_id)
FROM sys.foreign_keys
WHERE OBJECT_NAME(referenced_object_id) = #tableName AND
OBJECT_NAME(parent_object_id) != #tableName
EXEC DropDependentTables #dependentTableName
END
I'm going to leave a late answer (after around 10 years). I hope you'll find it handy.
In our company, we use this script to properly delete database tables. For each table, we first drop the dependencies (REFERENTIAL_CONSTRAINTS) then delete the table itself.
USE [database-name]
DECLARE #Sql NVARCHAR(500) DECLARE #Cursor CURSOR
SET #Cursor = CURSOR FAST_FORWARD FOR
SELECT DISTINCT sql = 'ALTER TABLE [' + tc2.TABLE_SCHEMA + '].[' + tc2.TABLE_NAME + '] DROP [' + rc1.CONSTRAINT_NAME + '];'
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc1
LEFT JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc2 ON tc2.CONSTRAINT_NAME =rc1.CONSTRAINT_NAME
OPEN #Cursor FETCH NEXT FROM #Cursor INTO #Sql
WHILE (##FETCH_STATUS = 0)
BEGIN
Exec sp_executesql #Sql
FETCH NEXT FROM #Cursor INTO #Sql
END
CLOSE #Cursor DEALLOCATE #Cursor
GO
EXEC sp_MSforeachtable 'DROP TABLE ?'
GO
The credit goes to a colleague of mine, Abolfazl Najafzade, for the script.

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