【问题标题】:Alter view after table rename or drop表重命名或删除后更改视图
【发布时间】:2020-01-18 04:49:04
【问题描述】:

我有以下示例数据。

--表格:

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 时处理这个异常。

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

我的尝试

--Procedure : 创建视图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

--重命名表:

exec sp_rename 'mtest2', 'mtest22';

--执行SP:

exec spmtest_createView;

--获取视图数据:

select * from mviewall;

但是拿不到。

【问题讨论】:

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


    【解决方案1】:

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

    现实世界更复杂,有人可以通过更改column type、添加/删除任何columns 来更改任何表,在所有这些情况下,您的create view 语句都会因为 union all 或中的类型不兼容而失败union 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并调用first proc....

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-24
      • 2022-08-21
      • 2012-12-05
      • 2016-09-19
      • 1970-01-01
      • 2013-03-14
      • 1970-01-01
      相关资源
      最近更新 更多