在mssql里基于多个表查询的视图,不允许使用instead of 触发器

在mssql里创建了一个基于多个表查询的视图,为何想对该视图做触发并将新增或更改的记录写到另一个表时,提示该视图已经存在了instead of 触发器了,

img

该回答引用ChatGPT

这个错误是因为基于多个表查询的视图不支持直接的 INSERT、UPDATE 或 DELETE 操作,而是只能进行 SELECT 操作。因此,如果您想要对该视图进行插入、更新或删除操作,并且希望通过触发器将这些操作记录到另一个表中,您需要创建一个 INSTEAD OF 触发器。

不过,如果在创建 INSTEAD OF 触发器时,系统提示该视图已经存在了 INSTEAD OF 触发器,那么您需要先删除已存在的触发器,然后再创建一个新的触发器来实现您的需求。您可以使用以下 SQL 语句来删除视图上的触发器:

DROP TRIGGER trigger_name ON view_name;

其中,trigger_name 是要删除的触发器的名称,view_name 是该触发器所附加的视图的名称。删除触发器后,您就可以创建一个新的触发器来记录对该视图的插入、更新或删除操作了。

参考GPT和自己的思路,在 SQL Server 中,如果一个视图被定义为基于多个表查询的视图,它是不允许使用 Instead Of 触发器的。这是因为 Instead Of 触发器可以在执行 insert、update 或 delete 操作时代替底层表的行为,但在多表视图中,视图并不是一张实际的表,而是基于多个表查询的结果集。

1 如果您想要对基于多个表查询的视图进行 insert、update 或 delete 操作,并将新增或更改的记录写入另一个表中,可以考虑使用 Instead Of 触发器的替代方案,例如:

2 创建一个包含需要插入或更新的记录的表,然后创建一个存储过程,将这个表作为输入参数传递给存储过程,并在存储过程中执行 insert、update 或 delete 操作,并将新增或更改的记录写入另一个表中。

在应用程序层面进行处理,将需要插入或更新的记录发送给一个 API,API 将这些记录转发给存储过程或直接执行 insert、update 或 delete 操作,并将新增或更改的记录写入另一个表中。

需要注意的是,在视图中不允许使用 Instead Of 触发器,但是可以使用 After 触发器。但是在 After 触发器中,不能修改视图的基础表,因为这会触发更多的触发器,导致死循环。因此,如果您需要在基于多个表查询的视图中使用触发器,建议将视图改为基于单个表的视图,然后使用 After 触发器。

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
在SQL Server中,一个视图本质上是一个虚拟表,可以被用作查询基础表并提供查询结果。与基本表不同,视图不包含实际的行和数据,而是在查询时基于相关表中的数据进行计算。视图通常由一个或多个基础表定义,并且可以用于简化复杂查询、隐藏敏感数据,以及按照需要区分查询权限。

关于“不允许使用instead of 触发器在mssql里创建了一个基于多个表查询的视图”的问题,答案是“不太确定”。从概念上讲,视图是只读的,它们不能被用作数据存储方式,也不能用于写入和更新数据。在这种情况下,你无法在视图上定义instead of触发器,因为这些触发器是用于实现对基础表的写操作的。

但是,如果你的视图基于多个表,而且需要将新增或更改的记录写入一个表中,可以考虑使用以下方法:

  1. 创建一个存储过程或触发器,在基础表上实现写操作,然后使用该存储过程或触发器来更新视图。

  2. 使用交互式更新视图,该视图必须定义为支持更新。在这种情况下,你可以使用INSERT、UPDATE或DELETE 记录语句更新视图。

下面是一个用于将新增的记录写入另一个表中的示例代码:

CREATE TRIGGER tr_insert_view_data
   ON view_name
   INSTEAD OF INSERT
AS
BEGIN
   DECLARE @table1_key int, @table2_key int, @value varchar(50)

   SELECT @table1_key = table1_key, @table2_key = table2_key, @value = value FROM inserted

   INSERT INTO other_table
   (table1_key, table2_key, value)
   VALUES
   (@table1_key, @table2_key, @value)

   INSERT INTO table1
   (table1_key, value)
   VALUES
   (@table1_key, @value)

   INSERT INTO table2
   (table2_key, value)
   VALUES
   (@table2_key, @value)
END

在这个例子中,我们假设view_name是一个基于table1和table2表的视图,我们需要将它的数据插入到other_table、table1和table2中。我们使用INSTEAD OF触发器来拦截插入语句并执行所需的操作。注意,我们还需要在视图上声明触发器,例如:

CREATE VIEW view_name AS
   SELECT table1.value, table2.value
   FROM table1
   INNER JOIN table2 ON table1.table1_key = table2.table2_key
GO

ALTER VIEW view_name
   WITH SCHEMABINDING
AS
   SELECT table1.value, table2.value
   FROM dbo.table1
   INNER JOIN dbo.table2 ON table1.table1_key = table2.table2_key
GO

CREATE TRIGGER tr_insert_view_data
   ON view_name
   INSTEAD OF INSERT
...

请注意, SCHEMABINDING必须在视图上声明 before触发器时使用。如果已经定义了instead of 触发器,请首先删除它们,然后为视图定义schema binding,然后再重新创建instead of 触发器。

希望这个例子可以帮助你!
如果我的回答解决了您的问题,请采纳!

在MSSQL中,一个视图是基于一个或多个表的查询结果创建的虚拟表,视图没有实际存储数据,只是对表数据的逻辑视图。在这种情况下,视图是不支持插入、更新和删除操作的,因为这些操作实际上并不直接针对表,而是针对视图。

因此,如果你想对视图进行触发器操作,需要使用instead of 触发器。这种类型的触发器可以模拟对视图的插入、更新和删除操作,以便在需要时将更改写入到表中。

如果在尝试创建instead of 触发器时提示视图已经存在了instead of 触发器,可能是因为该视图已经存在了一个或多个instead of 触发器。在这种情况下,你需要修改或删除现有的instead of 触发器,然后重新创建你需要的触发器。

要查看现有的视图触发器,请使用以下查询:

SELECT * FROM sys.triggers WHERE parent_class=1 AND parent_id = OBJECT_ID('YourViewName')


请注意,如果视图基于多个表进行联接,并且存在联接条件,则在使用instead of 触发器时,需要确保在视图中的所有表上都定义了相应的instead of 触发器。

不知道你这个问题是否已经解决, 如果还没有解决的话:

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^