我正在将ColdFusion项目从Oracle 11转换为MS SQL 2008.我使用SSMA转换数据库,包括触发器,过程和函数。序列映射到IDENTITY列。
我计划使用像
这样的INSERT语句INSERT INTO mytable (col1, col2)
OUTPUT INSERTED.my_id
values('val1', 'val2')
这会抛出一个错误,因为该表定义了一个触发器,AFTER INSERT会将一些INSERTED数据写入另一个表以保存数据的历史记录。
微软写道:
如果指定了OUTPUT子句而未指定INTO 关键字,DML操作的目标不能有任何启用 针对给定的DML操作在其上定义的触发器。例如,如果 OUTPUT子句在UPDATE语句(目标表)中定义 不能有任何启用的UPDATE触发器。 http://msdn.microsoft.com/en-us/library/ms177564.aspx
我现在想知道首先检索生成的id的最佳做法是什么,其次是在第二个表中“备份”INSERTED数据。
这是INSERT的好方法吗?它的工作原理是因为INSERTED值不是简单地返回而是写入INTO临时变量。它可以在微软描述的测试中运行,而不会引发有关触发器的错误。
<cfquery>
DECLARE @tab table(id int);
INSERT INTO mytable (col1, col2)
OUTPUT INSERTED.my_id INTO @tab
values('val1', 'val2');
SELECT id FROM @tab;
</cfquery>
我应该使用OUTPUT条款吗?当我必须在一个cfquery-block中编写多个子句时,我不应该更好地使用SELECT SCOPE_DENTITY()吗?
谢谢,最好的, 哈德
答案 0 :(得分:2)
我认为这就是你想要做的事情:
<cfquery name="qryInsert" datasource="db" RESULT="qryResults">
INSERT INTO mytable (col1, col2)
</cfquery>
<cfset id = qryResults.IDENTITYCOL>
答案 1 :(得分:1)
这似乎有效 - 行被插入,而不是触发器返回结果,后触发器不会干扰,后触发器按预期记录到表中:
CREATE TABLE dbo.x1(ID INT IDENTITY(1,1), x SYSNAME);
CREATE TABLE dbo.log_after(ID INT, x SYSNAME,
dt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP);
GO
CREATE TRIGGER dbo.x1_after
ON dbo.x1
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;
INSERT dbo.log_after(x) SELECT x FROM inserted;
END
GO
CREATE TRIGGER dbo.x1_before
ON dbo.x1
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @tab TABLE(id INT);
INSERT dbo.x1(x)
OUTPUT inserted.ID INTO @tab
SELECT x FROM inserted;
SELECT id FROM @tab;
END
GO
现在,如果你在cfquery
中写下这个,你应该在输出中找回一行。我不懂CF,所以我不确定是否必须看到某种select
知道它会返回一个结果集(但你可以在Management Studio中尝试确认我不是拉你的腿):
INSERT dbo.x1(x) SELECT N'foo';
现在您应该将后插入逻辑移动到此触发器。
请注意,现在您将获得多行(这与您从SCOPE_IDENTITY()
获得的单个结果略有不同)。这是一件好事,我只是想指出来。
答案 2 :(得分:0)
我必须承认,这是我第一次看到有人使用这样的合并方法而不是简单地使用内置PK检索并将其拆分为单独的数据库请求(example)。