如何在与身份一起使用的多表视图上编写INSTEAD OF INSERT触发器?

时间:2014-06-08 12:25:17

标签: sql sql-server view triggers identity-column

我有两个表具有1:1的关系,并使用IDENTITY列作为主键。

视图将两个表连接在一起,给人的印象是所有列都存储在一个表中。

出于查看目的,这很好,但视图也需要INSTEAD OF INSERT触发器。

如何编写这样的触发器,在两个表中拆分列值?

注意:除父表中的标识列之外没有候选键。否则这个问题可能有所帮助:

INSERT INTO View, INSTEAD OF Trigger, Identity, multiple tables?

(还有一种可能的解决方案,在该问题的答案中为每个字段声明一个变量。)

简化架构(我遗漏了PKEY,FKEY,COLLATIONS等):

CREATE TABLE
  [dbo].[parent]
(
    [parent_id] INT IDENTITY(1,1)
  , [name]      NVARCHAR(100)
)

CREATE TABLE
  [dbo].[child]
(
    [parent_id] INT NOT NULL
  , [child_id]  INT IDENTITY(1,1)
  , [name]      NVARCHAR(100)
)

GO

CREATE VIEW
  [dbo].[parent_child]
AS
SELECT
    par.[parent_id]
  , par.[name]      AS "parent_name"
  , chi.[child_id]
  , chi.[name]      AS "child_name"
FROM
  [dbo].[parent] par
LEFT OUTER JOIN
  [dbo].[child] chi
ON
  chi.[parent_id] = par.[parent_id]

GO

触发器模板:

CREATE TRIGGER
  [dbo].[parent_child_instead_of_insert]
ON
  [dbo].[parent_child]
INSTEAD OF INSERT
AS
BEGIN
  -- Implementation here
END
GO

示例数据:

INSERT INTO 
  [dbo].[parent_child]
(
    [parent_name]
  , [child_name]
)
SELECT 
    'parent1'
  , 'child1' 
UNION 
SELECT 
    'parent2'
  , 'child2'

2 个答案:

答案 0 :(得分:1)

受到Future-proofing an INSTEAD OF INSERT trigger问题的启发,我提出了一个使用临时表#inserted的解决方案,该表是inserted表的完整副本。

触发器在该表上添加一个临时标识列,以便可以使用唯一值迭代插入的行。

其余的是一个使用游标的简单循环,该游标首先将每一行插入父表,然后使用SCOPE_IDENTITY()插入子行。

此解决方案优于"为每列声明一个var"解决方案,您必须只获取临时标识值而不是所有列。

性能方面,它可能不太好,因为必须复制插入表中的所有数据。

SELECT * INTO [dbo].[#inserted] FROM [inserted]
ALTER TABLE [dbo].[#inserted] ADD [temp_id] INT IDENTITY(1,1)

DECLARE
  @temp_id int

DECLARE
  cur CURSOR
FOR
SELECT
  [temp_id]
FROM 
  [dbo].[#inserted]

OPEN cur
FETCH cur INTO @temp_id
WHILE @@FETCH_STATUS = 0
BEGIN

INSERT INTO 
  [dbo].[parent]
(
  [name]
)
SELECT
  [parent_name]
FROM
  [#inserted]
WHERE
  [temp_id] = @temp_id

INSERT INTO
  child
(
    [parent_id]
  , [name]
)
SELECT
    SCOPE_IDENTITY()
  , [child_name]
FROM
  [dbo].[#inserted]
WHERE
  [temp_id] = @temp_id

FETCH cur INTO @temp_id
END

CLOSE cur
DEALLOCATE cur

答案 1 :(得分:0)

您可以通过为每列声明一个变量来迭代inserted表。

DECLARE
  @parent_name NVARCHAR(100)

DECLARE
  @child_name NVARCHAR(100)

DECLARE
  cur CURSOR
FOR
SELECT
    [parent_name]
  , [child_name]
FROM 
  [inserted]

OPEN cur
FETCH cur INTO @parent_name, @child_name
WHILE @@FETCH_STATUS = 0
BEGIN

INSERT INTO 
  [dbo].[parent]
(
  [name]
)
SELECT
  @parent_name

INSERT INTO
  child
(
    [parent_id]
  , [name]
)
SELECT
    SCOPE_IDENTITY()
  , @child_name

FETCH cur INTO @parent_name, @child_name
END

CLOSE cur
DEALLOCATE cur

我从这个答案中得到了这个想法:https://stackoverflow.com/a/15162860/426242