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

时间:2019-09-17 10:24:20

标签: sql-server tsql sql-server-2008-r2

我有以下示例数据。

-表格:

create table mtest1
(
  id int,
  name varchar(10)
);
create table mtest2
(
  id int,
  name varchar(10)
);
create table mtest3
(
  id int,
  name varchar(10)
);
insert into mtest1 values(1,'mtest1');
insert into mtest2 values(1,'mtest2');
insert into mtest3 values(1,'mtest3');

-观看次数:

create view mview1 
as
select * from mtest1

create view mview2 
as
select * from mtest1
union all 
select * from mtest2

create view mview3
as
select * from mtest1
union all 
select * from mtest2
union all
select * from mtest3

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

例如:我重命名或删除了在视图mtest2mview2中引用的表mview3,并且我想更改那些出现无效对象{{ 1}}。

我的尝试

-程序:用于创建视图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 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 sp_rename 'mtest2', 'mtest22';

-获取视图数据:

exec spmtest_createView;

但无法获取。

1 个答案:

答案 0 :(得分:0)

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

现实世界更加复杂,有人可以通过更改column type,添加/删除任何columns来更改任何表,并且在所有这些情况下,您的create view语句都会由于不兼容而失败all all中的类型数,或all all每个成员中的列号不匹配。

当然,在您的*定义中使用view也总是很不好,任何column的简单重新创建(拖放)都会破坏您的视线。

因此,您应该只改变自己的方法,因为有太多事情可以更改,因此无法确保在动态代码中创建视图的安全。

也许在创建视图时使用with schemabinding选项对您很有用,它将停止任何更改基础表结构的尝试。


由于您的错误。 您的第一个proccatch block中以@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,' ')

我注释了原始代码的某些部分,以向您说明它返回了

null

这是因为通过删除一个基本表使视图'mview1'无效后,INFORMATION_SCHEMA.TABLES就会消失,因此您的inner join返回null

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

最后,最后一行调用以first proc结尾的cath block,该second proc调用执行null的{​​{1}}并调用first proc

幸运的是,一旦达到嵌套级别限制,此loop就会被服务器中断。