我有以下示例数据。
-表格:
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
时处理这个问题。
例如:我重命名或删除了在视图mtest2
和mview2
中引用的表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;
但无法获取。
答案 0 :(得分:0)
您的方法通常是错误的,因为您认为环境中唯一可以改变的就是任何表的存在。
现实世界更加复杂,有人可以通过更改column type
,添加/删除任何columns
来更改任何表,并且在所有这些情况下,您的create view
语句都会由于不兼容而失败all all中的类型数,或all all每个成员中的列号不匹配。
当然,在您的*
定义中使用view
也总是很不好,任何column
的简单重新创建(拖放)都会破坏您的视线。
因此,您应该只改变自己的方法,因为有太多事情可以更改,因此无法确保在动态代码中创建视图的安全。
也许在创建视图时使用with schemabinding
选项对您很有用,它将停止任何更改基础表结构的尝试。
由于您的错误。
您的第一个proc
在catch 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
就会被服务器中断。