sql - Microsoft SQL Server (MSSQL) 可更新 View ,具有多个基表和完整性能

标签 sql function view sql-server-2008-r2 updatable-views

我正在使用 MSSQL 2008 R2。它具有可更新 View 的方便功能。例如,如果我有一个表 t 将 id 映射到名称:

create table t (id int not null primary key, name varchar(100) not null unique)

然后是另一个表,提供一些 ID 和更多信息:
create table u (id int not null primary key references t, info varchar(100) not null)

为方便起见,有一个 View 可以让我看到 u 中的行增加了 name 列:
create view v as select u.*, t.name from u u join t t on u.id = t.id

然后我现在可以按名称而不是 id 进行更新:
update v set info = 'foo' where name = 'fred'

最方便。但是如果我想删除 'fred' 的行会发生什么?
delete v where name = 'fred' -- Fails

我收到错误

View or function 'v' is not updatable because the modification affects multiple base tables.



SQL Updatable View with joined tables 中所述(它指的是 Oracle,但 MSSQL 的情况似乎相同)您可以拥有多个基表的可更新 View ,只要只有一个保留键的表;粗略地说,这是表中的任何行在 View 中最多出现一次的地方。在上面的 View 中,我们可以看到 t 和 u 都是保留键的表。但是我们可以通过调整 View 定义来作弊:
create view v as
select u.*, (select t.name from t t where t.id = u.id) as name
from u u

这给出了与以前相同的行,但现在允许更新:
update v set info = 'foo' where name = 'fred'

从语义上讲,来自 t 的任何行在 View 中最多出现一次仍然是正确的,但是因为我们没有以正常方式加入 t,所以我们没有达到更新限制。此外,我们还可以从此 View 中删除:
delete from v where name = 'fred'

这是正确的,从基础表 u 中删除,而不是从 t 中删除。很明显,将之前的 View 表达为简单的连接,将无法判断“删除”操作应该从 u 还是从 t(或两者)中删除行。

对于许多“选择”查询,使用重写 View 的执行计划有点不同,所以我可能希望它在某些情况下执行得慢一点。很遗憾优化器无法看到(在这种特殊情况下,存在唯一索引)两个 View 具有相同的数据。

您还可以使用函数创建可更新的 View :
create function dbo.get_name(@id int) returns varchar(100) as begin
  declare @r varchar(100)
  select @r = name from t where id = @id
  return @r
end

create view v as select *, dbo.get_name(id) as name from u

这可以给出仍然不同(通常更复杂)的查询计划,因此它可能仍然更慢。

所以我们有两种可能的方法来制作可更新的 View ,但它们并不完全令人满意。让更新和删除操作工作会很好,但要确保 View 在选择查询上的性能不会比两个表的简单连接更差;也许您可以向查询引擎提供一些提示。有人可以提出建议吗?

最佳答案

(select t.name from t t where t.id = u.id)是一个非常 Macgyver 的技巧,您可以绕过对可删除表只有一张表的限制。

我可以建议的一种解决方案是使用而不是触发器,这将允许您个性化删除语句将对 View 执行的操作。

自定义触发器可能不会影响 View 的自动优化。

一些网站通过一些例子更深入地了解它:
http://blogs.msdn.com/b/anthonybloesch/archive/2009/02/16/insteadoftriggerspart1.aspx

http://www.mssqltips.com/sqlservertip/1804/using-instead-of-triggers-in-sql-server-for-dml-operations/

关于sql - Microsoft SQL Server (MSSQL) 可更新 View ,具有多个基表和完整性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21260839/

相关文章:

python - 使用 Jython 和 zxJDBC 进行具有多行值的 SQL INSET

sql - 如何在 SQLite 数据库中重新播种自动增量列?

sql - 检查 Postgres jsonb 是否包含以下值之一

javascript - 是否可以将 instanceof 运算符结果作为值获取?

EditText 上的android random NullPointerException

sql - 非标识列自增

r - 为什么 deparse(substitute(x)) 不选择 'x' 的名称

javascript - 如何编写接受回调作为参数的 jquery 函数

android - 如何根据其父 View 大小设置 ImageView 可绘制大小?

c# - Xamarin.Form 的 LayoutOptions,尤其是 Fill 和 Expand 之间有什么区别?