Sql server 表重命名或删除后更改视图

Sql server 表重命名或删除后更改视图,sql-server,tsql,sql-server-2008-r2,Sql Server,Tsql,Sql Server 2008 R2,我有以下样本数据 --表: --观点: 注意:现在我想创建一个视图,其中包含名为mviewall的所有其他视图。在创建视图mviewall之间,某些表被删除 我想在创建viewmviewall时处理这个异常 例如:我重命名或删除了视图mview2和mview3中引用的表mtest2,我想更改那些出现无效对象mtest2错误的视图 我的尝试: --过程:用于创建视图mviewall alter procedure spmtest_createView as begin declare @

我有以下样本数据

--表:

--观点:

注意:现在我想创建一个视图,其中包含名为
mviewall
的所有其他视图。在创建视图
mviewall
之间,某些表被删除 我想在创建view
mviewall
时处理这个异常

例如:我重命名或删除了视图
mview2
mview3
中引用的表
mtest2
,我想更改那些出现无效对象
mtest2
错误的视图

我的尝试

--过程:用于创建视图
mviewall

alter procedure spmtest_createView
as
begin

    declare @ErrorTable varchar(max)=''
    declare @ErrorView varchar(max) = ''
    declare @sql varchar(max) = ''

begin try

    if exists(select 1 from sys.views where name='mviewall' and type='v')
    drop view mviewall;

    set @sql = '
    create view mviewall 
    as 
    select * from mview1 
    union all 
    select * from mview2 
    union all 
    select * from mview3';
    print(@sql);
    exec(@sql);

end try
begin catch
    SELECT @ErrorTable = ERROR_MESSAGE(), @ErrorView = ERROR_PROCEDURE();
    SELECT @ErrorTable = REPLACE(@ErrorTable,'''','');
    SELECT @ErrorTable = SUBSTRING(@ErrorTable,CHARINDEX('dbo.',@ErrorTable),LEN(@ErrorTable)-CHARINDEX('dbo.',@ErrorTable))
    SELECT @ErrorTable = REPLACE(@ErrorTable,'dbo.','');
    print(@ErrorTable);
    print(@ErrorView);
    exec spalterview @ErrorTable,@ErrorView;

end catch   

end
--过程:用于alter view

alter procedure spalterview 
@ErrorTable varchar(255),
@ErrorView varchar(255)
as

begin

    DECLARE @Tables VARCHAR(MAX) = ''
    DECLARE @DSQL VARCHAR(MAX) = ''

    SELECT @Tables = STUFF((SELECT ' SELECT * FROM [dbo].['+vt.TABLE_NAME+'] UNION ALL ' 
    FROM INFORMATION_SCHEMA.VIEW_TABLE_USAGE vt
    INNER JOIN INFORMATION_SCHEMA.TABLES tbl ON vt.TABLE_NAME = tbl.TABLE_NAME AND vt.TABLE_CATALOG = tbl.TABLE_CATALOG
    WHERE VIEW_NAME = @ErrorView AND vt.TABLE_NAME <> @ErrorTable
    FOR XML PATH('')),1,1,' ')

    SET @Tables = LEFT(@Tables,LEN(@Tables)-10);

    SET @DSQL = 'ALTER VIEW ['+@ErrorView+'] AS 
                '+@Tables+';';

    print(@DSQL);
    EXEC(@DSQL);

    exec spmtest_createView; --Calling this because of multiple exception may occur  

end
--执行SP:

exec spmtest_createView;
--获取视图数据:

select * from mviewall;

但是无法得到它。

您的方法通常是错误的,因为您认为在您的环境中唯一可以改变的是任何表的存在

现实世界更为复杂,有人可以通过更改
列类型
、添加/删除任何
,来更改任何表,在所有这些情况下,您的
创建视图
语句将因union all中的类型不兼容或union all的每个成员中的列数不匹配而失败

因为,在
视图中使用
*
也总是不好的,任何
列的简单重新创建(拖放+添加)都会破坏您的视图

所以您应该改变您的方法,因为太多的事情可能会改变,所以没有办法在动态代码中安全地创建视图

在创建视图时,使用
和schemabinding
选项可能对您有用,它将停止任何更改底层表结构的尝试


现在谈谈你的错误。 第一个
proc
catch块中完成,并将
@ErrorTable='Invalid object name mtest1'
@ErrorView='mview1'
传递到第二个proc

第二个过程执行与此类似的代码:

SELECT --@Tables = 
--stuff((SELECT ' SELECT * FROM [dbo].['+vt.TABLE_NAME+'] UNION ALL ' 
vt.TABLE_NAME
FROM INFORMATION_SCHEMA.VIEW_TABLE_USAGE vt
INNER JOIN INFORMATION_SCHEMA.TABLES tbl ON vt.TABLE_NAME = tbl.TABLE_NAME AND vt.TABLE_CATALOG = tbl.TABLE_CATALOG
WHERE VIEW_NAME = 'mview1' AND vt.TABLE_NAME <>'Invalid object name mtest1'
--FOR XML PATH('')),1,1,' ')
这是因为只要您通过删除一个基表而使视图无效,就会从
信息\u SCHEMA.TABLES
中消失,因此您的
内部联接将返回
null

下一段代码将
@DSQL
设置为
null
,并执行
null

最后,最后一行调用在
cath块中完成的
first proc
,该块调用执行
null
second proc
,并调用
first proc

幸运的是,一旦达到嵌套级别限制,服务器就会中断该
循环

exec spmtest_createView;
select * from mviewall;
SELECT --@Tables = 
--stuff((SELECT ' SELECT * FROM [dbo].['+vt.TABLE_NAME+'] UNION ALL ' 
vt.TABLE_NAME
FROM INFORMATION_SCHEMA.VIEW_TABLE_USAGE vt
INNER JOIN INFORMATION_SCHEMA.TABLES tbl ON vt.TABLE_NAME = tbl.TABLE_NAME AND vt.TABLE_CATALOG = tbl.TABLE_CATALOG
WHERE VIEW_NAME = 'mview1' AND vt.TABLE_NAME <>'Invalid object name mtest1'
--FOR XML PATH('')),1,1,' ')
null