OUTPUT INTO 子句中可以使用哪些列?
Posted
技术标签:
【中文标题】OUTPUT INTO 子句中可以使用哪些列?【英文标题】:What columns can be used in OUTPUT INTO clause? 【发布时间】:2008-09-30 22:08:43 【问题描述】:我正在尝试构建一个映射表,以将表中新行的 ID 与从中复制它们的行关联起来。 OUTPUT INTO 子句似乎非常适合,但它的行为似乎不符合文档。
我的代码:
DECLARE @Missing TABLE (SrcContentID INT PRIMARY KEY )
INSERT INTO @Missing
( SrcContentID )
SELECT cshadow.ContentID
FROM Private.Content AS cshadow
LEFT JOIN Private.Content AS cglobal ON cshadow.Tag = cglobal.Tag
WHERE cglobal.ContentID IS NULL
PRINT 'Adding new content headers'
DECLARE @Inserted TABLE (SrcContentID INT PRIMARY KEY, TgtContentID INT )
INSERT INTO Private.Content
( Tag, Description, ContentDate, DateActivate, DateDeactivate, SortOrder, CreatedOn, IsDeleted, ContentClassCode, ContentGroupID, OrgUnitID )
OUTPUT cglobal.ContentID, INSERTED.ContentID INTO @Inserted (SrcContentID, TgtContentID)
SELECT Tag, Description, ContentDate, DateActivate, DateDeactivate, SortOrder, CreatedOn, IsDeleted, ContentClassCode, ContentGroupID, NULL
FROM Private.Content AS cglobal
INNER JOIN @Missing AS m ON cglobal.ContentID = m.SrcContentID
导致错误消息:
Msg 207, Level 16, State 1, Line 34
Invalid column name 'SrcContentID'.
(第 34 行是带有 OUTPUT INTO 的行)
实验表明,只有实际存在于 INSERT 目标中的行才能在 OUTPUT INTO 中选择。但这与在线书籍中的文档相矛盾。关于OUTPUT Clause的文章有一个描述类似用法的示例E:
OUTPUT INTO 子句返回值 从正在更新的表中 (WorkOrder) 以及来自产品 桌子。产品表用于 FROM 子句指定行 更新。
有人用过这个功能吗?
(与此同时,我已经重写了我的代码以使用游标循环来完成这项工作,但这很丑,我仍然很好奇)
【问题讨论】:
【参考方案1】:您可以在 Sql Server 2008 中使用 MERGE 来完成此操作。示例代码如下:
--drop table A
create table A (a int primary key identity(1, 1))
insert into A default values
insert into A default values
delete from A where a>=3
-- insert two values into A and get the new primary keys
MERGE a USING (SELECT a FROM A) AS B(a)
ON (1 = 0) -- ignore the values, NOT MATCHED will always be true
WHEN NOT MATCHED THEN INSERT DEFAULT VALUES -- always insert here for this example
OUTPUT $action, inserted.*, deleted.*, B.a; -- show the new primary key and source data
结果是
INSERT, 3, NULL, 1
INSERT, 4, NULL, 2
即对于每一行,新的主键 (3, 4) 和旧的主键 (1, 2)。创建一个名为例如的表#OUTPUT 并添加“ INTO #OUTPUT;”在 OUTPUT 子句的末尾将保存记录。
【讨论】:
MERGE 语句是我最好的新朋友 :) 这里有很好的解释和例子:sqlblog.com/blogs/jamie_thomson/archive/2010/01/06/… 把这个留在这里:mssqltips.com/sqlservertip/3074/…【参考方案2】:我已验证问题在于您只能使用 INSERTED
列。文档似乎表明您可以使用from_table_name
,但我似乎无法让它工作(无法绑定多部分标识符“m.ContentID”。):
TRUNCATE TABLE main
SELECT *
FROM incoming
SELECT *
FROM main
DECLARE @Missing TABLE (ContentID INT PRIMARY KEY)
INSERT INTO @Missing(ContentID)
SELECT incoming.ContentID
FROM incoming
LEFT JOIN main
ON main.ContentID = incoming.ContentID
WHERE main.ContentID IS NULL
SELECT *
FROM @Missing
DECLARE @Inserted TABLE (ContentID INT PRIMARY KEY, [Content] varchar(50))
INSERT INTO main(ContentID, [Content])
OUTPUT INSERTED.ContentID /* incoming doesn't work, m doesn't work */, INSERTED.[Content] INTO @Inserted (ContentID, [Content])
SELECT incoming.ContentID, incoming.[Content]
FROM incoming
INNER JOIN @Missing AS m
ON m.ContentID = incoming.ContentID
SELECT *
FROM @Inserted
SELECT *
FROM incoming
SELECT *
FROM main
显然,from_table_name
前缀只允许在 DELETE
或 UPDATE
(或 2008 年的 MERGE
)上使用 - 我不知道为什么:
from_table_name
是一个列前缀,用于指定包含在DELETE
或UPDATE
语句的FROM
子句中的表,用于指定要更新或删除的行。
如果正在修改的表也在FROM
子句中指定,则对该表中列的任何引用都必须使用INSERTED
或DELETED
前缀进行限定。
【讨论】:
【参考方案3】:我遇到了和你完全一样的问题,我感觉到你的痛苦...... 据我所知,没有办法将 from_table_name 前缀与 INSERT 语句一起使用。 我确信这有一个可行的技术原因,我很想知道它到底是什么。
好的,找到了,这里有一篇关于为什么它不起作用的论坛帖子: MSDN forums
【讨论】:
它提供了解决方案的线索。合并声明!然后@Simon 设法提供语法。不错!【参考方案4】:我想我找到了解决这个问题的方法,遗憾的是它涉及一个临时表,但至少它可以防止创建一个可怕的游标 :) 您需要做的是在要从中复制记录的表中添加一个额外的列,并为其指定一个“唯一标识符”类型。
然后声明一个临时表:
DECLARE @tmptable TABLE (uniqueid uniqueidentifier, original_id int, new_id int)
像这样将数据插入到您的临时表中:
insert into @tmptable
(uniqueid,original_id,new_id)
select NewId(),id,0 from OriginalTable
继续进行真正的插入到原始表中:
insert into OriginalTable
(uniqueid)
select uniqueid from @tmptable
现在将新创建的标识值添加到您的临时表中:
update @tmptable
set new_id = o.id
from OriginalTable o inner join @tmptable tmp on tmp.uniqueid = o.uniqueid
现在您有一个查找表,将新 id 和原始 id 保存在一条记录中,供您使用 :)
我希望这对某人有所帮助...
【讨论】:
谢谢,但如果我需要跟踪的密钥是唯一标识符,这只是一个可行的解决方案。我要解决的整个问题是跟踪分配给新行的 IDENTITY 值。【参考方案5】:(MS) 如果正在修改的表也在 FROM 子句中指定,则对该表中列的任何引用都必须使用 INSERTED 或 DELETED 前缀进行限定。
在您的示例中,您不能在 OUTPUT 中使用 cglobal 表,除非它是 INSERTED.column_name 或 DELETED.column_name:
INSERT INTO Private.Content
(Tag)
OUTPUT cglobal.ContentID, INSERTED.ContentID
INTO @Inserted (SrcContentID, TgtContentID)
SELECT Tag
FROM Private.Content AS cglobal
INNER JOIN @Missing AS m ON cglobal.ContentID = m.SrcContentID
对我有用的是一个简单的别名表,如下所示:
INSERT INTO con1
(Tag)
OUTPUT **con2**.ContentID, INSERTED.ContentID
INTO @Inserted (SrcContentID, TgtContentID)
SELECT Tag
FROM Private.Content con1
**INNER JOIN Private.Content con2 ON con1.id=con2.id**
INNER JOIN @Missing AS m ON con1.ContentID = m.SrcContentID
【讨论】:
以上是关于OUTPUT INTO 子句中可以使用哪些列?的主要内容,如果未能解决你的问题,请参考以下文章
如果语句包含没有 INTO 子句的 OUTPUT 子句,则 DML 语句不能有任何启用的触发器
如果语句包含没有 INTO 子句的 OUTPUT 子句,则 DML 语句的目标表“RECEIPT”不能有任何启用的触发器
使用 insert into select 将源列添加到输出子句
简单选择给了我:PLS-00428:需要一个 INTO 子句[重复]