- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
这是在 Azure 上。
我有一个父类(super class)型实体和几个子类型实体,后者需要在每次插入时从父类(super class)型实体的主键获取其外键。在 Oracle 中,我使用 BEFORE INSERT
触发来完成此操作。如何在 SQL Server/T-SQL 中实现这一目标?
DDL
CREATE TABLE super (
super_id int IDENTITY(1,1)
,subtype_discriminator char(4) CHECK (subtype_discriminator IN ('SUB1', 'SUB2')
,CONSTRAINT super_id_pk PRIMARY KEY (super_id)
);
CREATE TABLE sub1 (
sub_id int IDENTITY(1,1)
,super_id int NOT NULL
,CONSTRAINT sub_id_pk PRIMARY KEY (sub_id)
,CONSTRAINT sub_super_id_fk FOREIGN KEY (super_id) REFERENCES super (super_id)
);
我希望插入sub1
触发一个触发器,该触发器实际上将一个值插入 super
并使用 super_id
生成并放入 sub1
.
在 Oracle 中,这可以通过以下方式完成:
CREATE TRIGGER sub_trg
BEFORE INSERT ON sub1
FOR EACH ROW
DECLARE
v_super_id int; //Ignore the fact that I could have used super_id_seq.CURRVAL
BEGIN
INSERT INTO super (super_id, subtype_discriminator)
VALUES (super_id_seq.NEXTVAL, 'SUB1')
RETURNING super_id INTO v_super_id;
:NEW.super_id := v_super_id;
END;
鉴于 T-SQL 缺少 BEFORE INSERT
,请告知我如何在 T-SQL 中模拟这一点。能力?
最佳答案
有时是BEFORE
触发器可以替换为 AFTER
一,但在您的情况下似乎并非如此,因为您显然需要在插入发生之前提供一个值。因此,为此目的,最接近的功能似乎是 INSTEAD OF
触发一,如 @marc_s has suggested在他的评论中。
但请注意,正如这两种触发器类型的名称所示,BEFORE
之间存在根本区别。触发器和 INSTEAD OF
一。在这两种情况下,触发器都是在调用触发器的语句确定的操作尚未发生时执行的,在 INSTEAD OF
的情况下。触发该操作根本不应该发生。您需要完成的实际操作必须由触发器本身来完成。这与 BEFORE
非常不同触发器功能,其中语句始终要执行,当然,除非您显式地将其回滚。
但实际上还有一个问题需要解决。正如您的 Oracle 脚本所示,您需要转换的触发器使用 SQL Server 不支持的另一个功能,即 FOR EACH ROW
的功能。 。 SQL Server 中也没有每行触发器,只有每语句触发器。这意味着您需要始终牢记插入的数据是行集合,而不仅仅是一行。这增加了更多的复杂性,尽管这可能会结束您需要考虑的事项列表。
所以,实际上有两件事需要解决:
替换 BEFORE
功能;
替换 FOR EACH ROW
功能。
我解决这些问题的尝试如下:
CREATE TRIGGER sub_trg
ON sub1
INSTEAD OF INSERT
AS
BEGIN
DECLARE @new_super TABLE (
super_id int
);
INSERT INTO super (subtype_discriminator)
OUTPUT INSERTED.super_id INTO @new_super (super_id)
SELECT 'SUB1' FROM INSERTED;
INSERT INTO sub (super_id)
SELECT super_id FROM @new_super;
END;
这就是上面的工作原理:
与插入 sub1
中的行数相同首先添加到super
。生成的super_id
值存储在临时存储中(名为 @new_super
的表变量)。
新插入的super_id
s 现在插入 sub1
.
其实没什么太难的,但只有当 sub1
中没有其他列时,上述内容才有效。比您在问题中指定的那些。如果还有其他列,上面的触发器将需要更复杂一些。
问题是分配新的 super_id
分别到每个插入的行。实现映射的一种方法如下所示:
CREATE TRIGGER sub_trg
ON sub1
INSTEAD OF INSERT
AS
BEGIN
DECLARE @new_super TABLE (
<b>rownum int IDENTITY (1, 1),</b>
super_id int
);
INSERT INTO super (subtype_discriminator)
OUTPUT INSERTED.super_id INTO @new_super (super_id)
SELECT 'SUB1' FROM INSERTED;
WITH enumerated AS (
SELECT *, ROW_NUMBER() OVER (ORDER BY (SELECT 1)) AS rownum
FROM inserted
)
INSERT INTO sub1 (super_id, <i>other columns</i>)
SELECT n.super_id, i.<i>other columns</i>
FROM enumerated AS i
INNER JOIN @new_super AS n
ON i.rownum = n.rownum;
END;
如您所见,IDENTIY(1,1)
列添加到 @new_user
,所以暂时插入super_id
值将从 1 开始额外枚举。提供新 super_id
之间的映射。 s 和新数据行 ROW_NUMBER
函数用于枚举INSERTED
行也是如此。结果, INSERTED
中的每一行现在可以将集合链接到单个 super_id
从而补充了要插入 sub1
的完整数据行.
注意新的super_id
的顺序插入的顺序可能与分配的顺序不匹配。我认为这不是问题。全新super
生成的行除了 ID 之外都是相同的。因此,您所需要的只是获取一个新的 super_id
每新sub1
行。
但是,如果插入 super
的逻辑更复杂,由于某种原因,您需要准确记住哪个新 super_id
已生成新的 sub
行,您可能需要考虑此 Stack Overflow 问题中讨论的映射方法:
关于sql-server - 如何在 T-SQL/SQL Server 中模拟超/子类型(继承)实体的 BEFORE INSERT 触发器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15458006/
我是一名优秀的程序员,十分优秀!