我有两个表具有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'
答案 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