我问这个问题的方式是尝试了解我遇到的类似情况,并尝试了解插入视图是如何工作的。
我有这些表:
Create table A([id] int primary key not null, value nvarchar(50) NULL)
Create table B([id] int primary key not null, value nvarchar(50) NULL)
Run Code Online (Sandbox Code Playgroud)
我从两个表创建视图,如下所示:
create View V as (select * from A) UNION ALL (select * from B)
Run Code Online (Sandbox Code Playgroud)
我在 V 视图上有这个触发器:
Create trigger v_trig on V instead of insert AS
insert into v (id,value) select id,value from inserted
Run Code Online (Sandbox Code Playgroud)
当我尝试插入到我的视图中时,出现以下错误:
消息 4436,级别 16,状态 12,过程 v_trig,第 2 行
UNION ALL 视图“db.dbo.V”不可更新,因为未找到分区列
我有一个具有类似视图(带有union all)的数据库,出于某种原因,我可以毫无问题地插入它,我试图理解为什么。
我应该怎么做才能允许插入到诸如视图之类的视图中?有没有办法以插入的方式决定(不更改触发器)哪个是视图的默认表?
您只能在插入分区视图时执行此操作(触发器无关) ,该视图可以存储基础表具有与 a不相交的适当约束UNION ALL的数据,因此 an会明确地进入一个基础表。CHECKprimary keyINSERT
按照您的示例,如果您限制 table 的某些值A、 table 的其他值B并添加复合主键:
Create table A(
[id] int,
value nvarchar(50),
CHECK (value = 'A'),
PRIMARY KEY (ID, value))
Create table B(
[id] int,
value nvarchar(50),
CHECK (value = 'B'),
PRIMARY KEY (ID, value))
Run Code Online (Sandbox Code Playgroud)
视图保持不变:
create View V as (select id, value from A) UNION ALL (select id, value from B)
Run Code Online (Sandbox Code Playgroud)
现在您可以成功地直接插入到视图中(不需要触发器):
insert into v (id, value) select 1,'B'
-- (1 row(s) affected)
Run Code Online (Sandbox Code Playgroud)
有没有办法以插入的方式决定(不更改触发器)哪个是视图的默认表?
插入 with 与for 表(分区列)value = 'B'匹配,因此该行会自动按此方式插入。由于检查列必须是主键的一部分,因此 SQL 引擎知道该行属于该表而不属于任何其他表,因为它们都具有具有相同列和不同检查值的主键。您无法手动控制它。CHECKB
如果您尝试插入任何约束都不支持的值CHECK...
insert into v (id, value) select 1,'C'
--Msg 4457, Level 16, State 1, Line 1
--The attempted insert or update of the partitioned view failed because the value of the partitioning column does not belong to any of the partitions.
--The statement has been terminated.
Run Code Online (Sandbox Code Playgroud)
检查视图插入起作用的表的 DDL,您将看到不相交的CHECK约束。