如何使用 INSTEAD OF 触发器获取新记录的标识 INSERTED into table
How to get Identity of new records INSERTED into table with INSTEAD OF trigger
我在 table 上使用 INSTEAD OF 插入触发器来设置该行的递增版本号,并将该行复制到第二个 history/audit table.
这些行被插入到两个 table 中没有问题。
但是,我无法 return 将第一个 table 的新身份返回给用户。
架构
CREATE TABLE Table1
(
id INT IDENTITY(1,1) PRIMARY KEY,
name VARCHAR(250) NOT NULL UNIQUE,
rowVersion INT NOT NULL
)
CREATE TABLE Table1History
(
id INT NOT NULL,
name VARCHAR(250) NOT NULL,
rowVersion INT NOT NULL
)
CREATE TRIGGER TRG_INS_Table1
ON Table1
INSTEAD OF INSERT
AS
DECLARE @OutputTbl TABLE (id INT, name VARCHAR(250))
BEGIN
--make the insert
INSERT INTO Table1 (name, rowVersion)
OUTPUT INSERTED.id, INSERTED.name INTO @OutputTbl(id, name)
SELECT i.name, 1
FROM INSERTED i
--copy into history table
INSERT INTO Table1History (id, name, rowVersion)
SELECT t.ID, i.name, 1
FROM INSERTED i
JOIN @OutputTbl t on i.name = t.name
END
CREATE TRIGGER TRG_UPD_Table1
ON Table1
INSTEAD OF UPDATE
AS
BEGIN
--make the update
UPDATE Table1
SET name = i.name,
rowVersion = (SELECT d.rowVersion + 1 FROM DELETED d WHERE d.id = i.id)
FROM INSERTED i
WHERE Table1.id = i.id
--copy into history table
INSERT INTO Table1History (id, name, rowVersion)
SELECT i.id ,i.name, (SELECT d.rowVersion + 1 FROM DELETED d WHERE d.id = i.id)
FROM INSERTED i
END
在插入触发器中加入name
列并不理想,但它需要一次处理多个插入。
例如 INSERT INTO Table1 (name) VALUES('xxx'),('yyy')
尝试过的解决方案
进行插入时,SCOPE_IDENTITY
为 NULL
。
INSERT INTO Table1(name)
VALUES('xxx')
SELECT SCOPE_IDENTITY()
or
INSERT INTO Table1(name)
VALUES('xxx')
RETURN SCOPE_IDENTITY()
我也尝试过使用 OUTPUT - returns 0
:
DECLARE @IdentityOutput TABLE (id INT)
INSERT INTO Table1(name)
OUTPUT INSERTED.id INTO @IdentityOutput
VALUES('xxx')
SELECT id FROM @IdentityOutput
这些行插入得很好并且有 ID,但我无法访问它们,除非我使用下面的 - 这看起来很老套:
INSERT INTO Table1(name)
VALUES('xxx')
SELECT id from Table1 WHERE name = 'xxx'
获取新ID的正确方法是什么?
解决方案
不可能!在具有 INSTEAD OF 触发器的 table 上执行 INSERT 时,您无法可靠地 return 标识。 下面是针对我的情况的一个很好的解决方法(将 INSTEAD OF 触发器替换为 AFTER 触发器并添加了 DEFAULT 列)。
CREATE TABLE Table1
(
id INT IDENTITY(1,1) PRIMARY KEY,
name VARCHAR(250) NOT NULL UNIQUE,
rowVersion INT NOT NULL
)
GO
CREATE TABLE Table1History
(
id INT NOT NULL,
name VARCHAR(250) NOT NULL,
rowVersion INT NOT NULL
)
GO
CREATE TRIGGER TRG_INS_Table1
ON Table1
INSTEAD OF INSERT
AS
DECLARE @OutputTbl TABLE (id INT, name VARCHAR(250))
BEGIN
--make the insert
INSERT INTO Table1 (name, rowVersion)
SELECT i.name, 1
FROM INSERTED i
END
GO
CREATE TRIGGER TRG_UPD_Table1
ON Table1
INSTEAD OF UPDATE
AS
BEGIN
--make the update
UPDATE Table1
SET name = i.name,
rowVersion = (SELECT d.rowVersion + 1 FROM DELETED d WHERE d.id = i.id)
FROM INSERTED i
WHERE Table1.id = i.id
END
GO
CREATE TRIGGER TRG_AFT_INS_Table1
ON Table1
AFTER INSERT, UPDATE
AS
BEGIN
INSERT INTO Table1History (id, name, rowVersion)
SELECT i.ID, i.name, i.rowversion
FROM INSERTED i
END
GO
INSERT INTO Table1 (name) VALUES('xxx'),('yyy')
SELECT * FROM Table1History
-----------------------------------------------
id name rowVersion
2 yyy 1
1 xxx 1
-----------------------------------------------
UPDATE Table1 SET name = 'xxx1' WHERE id = 1;
SELECT * FROM Table1History
-----------------------------------------------
id name rowVersion
2 yyy 1
1 xxx 1
1 xxx1 2
-----------------------------------------------
基本上你不需要 TRG_INS_Table1 触发器,你可以只对列使用 DEFAULT value = 1 就可以了。此外,如果您使用 DATETIME 列而不是 rowversion,则只需将 INSERTED table 的状态插入到具有 GETDATE() 值的历史记录中。在那种情况下,您可以按 Dtime 列 DESC 排序,并且您有历史记录。
我在 table 上使用 INSTEAD OF 插入触发器来设置该行的递增版本号,并将该行复制到第二个 history/audit table.
这些行被插入到两个 table 中没有问题。
但是,我无法 return 将第一个 table 的新身份返回给用户。
架构
CREATE TABLE Table1
(
id INT IDENTITY(1,1) PRIMARY KEY,
name VARCHAR(250) NOT NULL UNIQUE,
rowVersion INT NOT NULL
)
CREATE TABLE Table1History
(
id INT NOT NULL,
name VARCHAR(250) NOT NULL,
rowVersion INT NOT NULL
)
CREATE TRIGGER TRG_INS_Table1
ON Table1
INSTEAD OF INSERT
AS
DECLARE @OutputTbl TABLE (id INT, name VARCHAR(250))
BEGIN
--make the insert
INSERT INTO Table1 (name, rowVersion)
OUTPUT INSERTED.id, INSERTED.name INTO @OutputTbl(id, name)
SELECT i.name, 1
FROM INSERTED i
--copy into history table
INSERT INTO Table1History (id, name, rowVersion)
SELECT t.ID, i.name, 1
FROM INSERTED i
JOIN @OutputTbl t on i.name = t.name
END
CREATE TRIGGER TRG_UPD_Table1
ON Table1
INSTEAD OF UPDATE
AS
BEGIN
--make the update
UPDATE Table1
SET name = i.name,
rowVersion = (SELECT d.rowVersion + 1 FROM DELETED d WHERE d.id = i.id)
FROM INSERTED i
WHERE Table1.id = i.id
--copy into history table
INSERT INTO Table1History (id, name, rowVersion)
SELECT i.id ,i.name, (SELECT d.rowVersion + 1 FROM DELETED d WHERE d.id = i.id)
FROM INSERTED i
END
在插入触发器中加入name
列并不理想,但它需要一次处理多个插入。
例如 INSERT INTO Table1 (name) VALUES('xxx'),('yyy')
尝试过的解决方案
进行插入时,SCOPE_IDENTITY
为 NULL
。
INSERT INTO Table1(name)
VALUES('xxx')
SELECT SCOPE_IDENTITY()
or
INSERT INTO Table1(name)
VALUES('xxx')
RETURN SCOPE_IDENTITY()
我也尝试过使用 OUTPUT - returns 0
:
DECLARE @IdentityOutput TABLE (id INT)
INSERT INTO Table1(name)
OUTPUT INSERTED.id INTO @IdentityOutput
VALUES('xxx')
SELECT id FROM @IdentityOutput
这些行插入得很好并且有 ID,但我无法访问它们,除非我使用下面的 - 这看起来很老套:
INSERT INTO Table1(name)
VALUES('xxx')
SELECT id from Table1 WHERE name = 'xxx'
获取新ID的正确方法是什么?
解决方案
不可能!在具有 INSTEAD OF 触发器的 table 上执行 INSERT 时,您无法可靠地 return 标识。
CREATE TABLE Table1
(
id INT IDENTITY(1,1) PRIMARY KEY,
name VARCHAR(250) NOT NULL UNIQUE,
rowVersion INT NOT NULL
)
GO
CREATE TABLE Table1History
(
id INT NOT NULL,
name VARCHAR(250) NOT NULL,
rowVersion INT NOT NULL
)
GO
CREATE TRIGGER TRG_INS_Table1
ON Table1
INSTEAD OF INSERT
AS
DECLARE @OutputTbl TABLE (id INT, name VARCHAR(250))
BEGIN
--make the insert
INSERT INTO Table1 (name, rowVersion)
SELECT i.name, 1
FROM INSERTED i
END
GO
CREATE TRIGGER TRG_UPD_Table1
ON Table1
INSTEAD OF UPDATE
AS
BEGIN
--make the update
UPDATE Table1
SET name = i.name,
rowVersion = (SELECT d.rowVersion + 1 FROM DELETED d WHERE d.id = i.id)
FROM INSERTED i
WHERE Table1.id = i.id
END
GO
CREATE TRIGGER TRG_AFT_INS_Table1
ON Table1
AFTER INSERT, UPDATE
AS
BEGIN
INSERT INTO Table1History (id, name, rowVersion)
SELECT i.ID, i.name, i.rowversion
FROM INSERTED i
END
GO
INSERT INTO Table1 (name) VALUES('xxx'),('yyy')
SELECT * FROM Table1History
-----------------------------------------------
id name rowVersion
2 yyy 1
1 xxx 1
-----------------------------------------------
UPDATE Table1 SET name = 'xxx1' WHERE id = 1;
SELECT * FROM Table1History
-----------------------------------------------
id name rowVersion
2 yyy 1
1 xxx 1
1 xxx1 2
-----------------------------------------------
基本上你不需要 TRG_INS_Table1 触发器,你可以只对列使用 DEFAULT value = 1 就可以了。此外,如果您使用 DATETIME 列而不是 rowversion,则只需将 INSERTED table 的状态插入到具有 GETDATE() 值的历史记录中。在那种情况下,您可以按 Dtime 列 DESC 排序,并且您有历史记录。