SQL 服务器给出无法访问的代码错误
SQL Server gives error to unreachable code
我们有以下案例:
我们有一个 SQL 服务器数据库和一个 table CL_Example
和另一个数据库,它有一个同名的视图 CL_Example
。此视图是使用多个 table 和内部联接创建的。
CL_Example
视图的结构与CL_Example
table相同
我们有一个 SQL 脚本,它将在这两个数据库上执行。如果它发现 CL_Example
作为 table,它应该插入数据,如果它发现 CL_Example
作为视图,那么它不应该插入数据。
但是当我们在 CL_Example
是一个视图的数据库上执行脚本时,我们得到以下错误:
Update or insert of view or function 'dbo.CL_Example' failed because it contains a derived or constant field.
即使 CL_Example
是视图的数据库无法访问插入语句,也会生成此错误。能否禁止这个错误,继续在两个数据库中执行脚本?
SQL服务器在执行前批量编译所有语句。
这将是一个编译时错误并停止批编译(引用不存在的对象会导致语句延迟编译,它会在语句执行时再次尝试,但这在这里不适用)。
如果批处理可能需要 运行 此类问题陈述,您需要将它们移动到不同的范围,以便仅在满足您的控制流条件时才编译它们。
通常最简单的方法是将整个问题陈述包装在 EXEC('')
中
IF OBJECT_ID('dbo.CL_Example', 'U') IS NOT NULL /*It is a table*/
EXEC('UPDATE dbo.CL_Example ....')
或者如果它不是静态字符串并且您需要向其传递参数,则使用 sys.sp_executesql
。
我可以建议另一种方法来解决您的问题。如果 CL_Example
是视图,而不是将查询固定为不插入,您可以在视图 INSTEAD OF INSERT
上创建触发器,它什么也不做,您不必担心插入查询。
示例:
create view vw_test
as
select 1 as a, 2 as b;
go
select * from vw_test;
go
if (1=2)
begin
insert into vw_test (a,b) values (3,4); -- unreachable but fails
end
go
create trigger tg_fake_insert on vw_test
instead of insert
as
begin
set nocount on;
end;
go
if (1=2)
begin
insert into vw_test (a,b) values (3,4); --unreachable, does not fail
end
else
begin
insert into vw_test (a,b) values (3,4); --actually works
end
go
您甚至可能想在该触发器中放置一些实际逻辑并将数据转移到其他地方?
编辑:要多加思考 - 如果您使用视图替换 table 以使遗留代码正常工作 - 您 应该 处理 insert/update/delete 可能发生的情况,好的方法是使用 instead of
触发器。
我们有以下案例:
我们有一个 SQL 服务器数据库和一个 table
CL_Example
和另一个数据库,它有一个同名的视图CL_Example
。此视图是使用多个 table 和内部联接创建的。CL_Example
视图的结构与CL_Example
table相同我们有一个 SQL 脚本,它将在这两个数据库上执行。如果它发现
CL_Example
作为 table,它应该插入数据,如果它发现CL_Example
作为视图,那么它不应该插入数据。
但是当我们在 CL_Example
是一个视图的数据库上执行脚本时,我们得到以下错误:
Update or insert of view or function 'dbo.CL_Example' failed because it contains a derived or constant field.
即使 CL_Example
是视图的数据库无法访问插入语句,也会生成此错误。能否禁止这个错误,继续在两个数据库中执行脚本?
SQL服务器在执行前批量编译所有语句。
这将是一个编译时错误并停止批编译(引用不存在的对象会导致语句延迟编译,它会在语句执行时再次尝试,但这在这里不适用)。
如果批处理可能需要 运行 此类问题陈述,您需要将它们移动到不同的范围,以便仅在满足您的控制流条件时才编译它们。
通常最简单的方法是将整个问题陈述包装在 EXEC('')
IF OBJECT_ID('dbo.CL_Example', 'U') IS NOT NULL /*It is a table*/
EXEC('UPDATE dbo.CL_Example ....')
或者如果它不是静态字符串并且您需要向其传递参数,则使用 sys.sp_executesql
。
我可以建议另一种方法来解决您的问题。如果 CL_Example
是视图,而不是将查询固定为不插入,您可以在视图 INSTEAD OF INSERT
上创建触发器,它什么也不做,您不必担心插入查询。
示例:
create view vw_test
as
select 1 as a, 2 as b;
go
select * from vw_test;
go
if (1=2)
begin
insert into vw_test (a,b) values (3,4); -- unreachable but fails
end
go
create trigger tg_fake_insert on vw_test
instead of insert
as
begin
set nocount on;
end;
go
if (1=2)
begin
insert into vw_test (a,b) values (3,4); --unreachable, does not fail
end
else
begin
insert into vw_test (a,b) values (3,4); --actually works
end
go
您甚至可能想在该触发器中放置一些实际逻辑并将数据转移到其他地方?
编辑:要多加思考 - 如果您使用视图替换 table 以使遗留代码正常工作 - 您 应该 处理 insert/update/delete 可能发生的情况,好的方法是使用 instead of
触发器。