Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/73.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
合并/插入/删除SQL命令中有多个输出子句?_Sql_Sql Server_Tsql - Fatal编程技术网

合并/插入/删除SQL命令中有多个输出子句?

合并/插入/删除SQL命令中有多个输出子句?,sql,sql-server,tsql,Sql,Sql Server,Tsql,我有一个T-SQL脚本,它使用MERGEs和INSERTs中的OUTPUT子句实现一些同步逻辑 现在,我在它上面添加了一个日志层,我想添加第二个OUTPUT子句来将值写入报告表 我可以在我的MERGE语句中添加第二个OUTPUT子句: MERGE TABLE_TARGET AS T USING TABLE_SOURCE AS S ON (T.Code = S.Code) WHEN MATCHED AND T.IsDeleted = 0x0 THEN UPDATE SET .... WH

我有一个
T-SQL
脚本,它使用
MERGE
s和
INSERT
s中的
OUTPUT
子句实现一些同步逻辑

现在,我在它上面添加了一个日志层,我想添加第二个
OUTPUT
子句来将值写入报告表

我可以在我的
MERGE
语句中添加第二个
OUTPUT
子句:

MERGE TABLE_TARGET AS T
USING TABLE_SOURCE AS S
ON (T.Code = S.Code) 
WHEN MATCHED AND T.IsDeleted = 0x0
    THEN UPDATE SET ....
WHEN NOT MATCHED BY TARGET 
    THEN INSERT ....
OUTPUT inserted.SqlId, inserted.IncId
INTO @sync_table
OUTPUT $action, inserted.Name, inserted.Code;
这是可行的,但只要我尝试添加目标

INTO @report_table;
我在进入之前收到以下错误消息:

A MERGE statement must be terminated by a semicolon (;)
我找到了,但它没有进一步帮助我,因为我要插入的字段在两个表之间没有重叠,我不想修改工作同步逻辑(如果可能的话)

更新:

在回答之后,我有了另一个想法,并重新编写了我的问题,如下所示:

INSERT INTO @report_table (action, name, code)
SELECT M.Action, M.Name, M.Code
FROM
(
MERGE TABLE_TARGET AS T
USING TABLE_SOURCE AS S
ON (T.Code = S.Code) 
WHEN MATCHED AND T.IsDeleted = 0x0
    THEN UPDATE SET ....
WHEN NOT MATCHED BY TARGET 
    THEN INSERT ....
OUTPUT inserted.SqlId, inserted.IncId
INTO @sync_table
OUTPUT $action as Action, inserted.Name, inserted.Code
) M
不幸的是,此方法也不起作用,运行时会输出以下错误消息:

An OUTPUT INTO clause is not allowed in a nested INSERT, UPDATE, DELETE, or MERGE statement.
因此,在一个DML语句中绝对不可能有多个
输出
子句。

不可能。看

Merge语句已被删除

[ <output_clause> ]
[]
方括号显示它可以有一个可选的输出子句。这方面的语法是

<output_clause>::=
{
    [ OUTPUT <dml_select_list> INTO { @table_variable | output_table }
        [ (column_list) ] ]
    [ OUTPUT <dml_select_list> ]
}
::=
{
[输出到{@table_variable | OUTPUT_table}
[(列清单)]]
[输出]
}
此子句可以同时具有
输出到
输出
,但不能同时具有两个


如果允许多个,语法将有
[,…n]

Martin Smith是正确的,在一个
合并
语句中不可能有两个
输出到
子句中,但他也正确地认为可以有一个
输出到
和一个
输出到
子句中
OUTPUT-INTO
将其结果集直接插入给定的表中,简单的
OUTPUT
将结果集返回给调用者

因此,您可以将
MERGE
语句包装到存储过程中,然后使用
INSERT。。。EXEC
将简单
输出的结果集插入第二个表

CREATE PROCEDURE [dbo].[TestMerge]
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;

    MERGE TABLE_TARGET AS T
    USING TABLE_SOURCE AS S
    ON (T.Code = S.Code) 
    WHEN MATCHED AND T.IsDeleted = 0x0
        THEN UPDATE SET ....
    WHEN NOT MATCHED BY TARGET 
        THEN INSERT ....
    OUTPUT inserted.SqlId, inserted.IncId
    INTO sync_table
    OUTPUT $action AS MergeAction, inserted.Name, inserted.Code;
END
用法

INSERT INTO report_table
EXEC [dbo].[TestMerge];
这将在
sync_表
report_表
中插入行

如果您检查执行计划,您将看到
INSERT。。。EXEC
在幕后创建一个临时表(另请参见
(亚当·麦卡尼奇)

很抱歉,我重提了一个旧线程,但我刚刚遇到了这个问题,并使用了一个实用的解决方案,而不是技术性的,可能是也可能不是显而易见的

正如前面所讨论的,MERGE并不是为实现这一点而设计的。INSERT_INTO…EXEC解决方案是一个很好的解决方案,但我正在处理的特定存储过程已经足够复杂了

所以为了让下一个需要处理这段代码的人能够简单地处理这段代码,我只使用了两个MERGE语句……一个执行插入操作,另一个执行更新操作。毕竟,没有法律规定你只能使用一个。我在日志记录表中添加了一个“action”列,在其中插入MERGE语句“insert”或“Update”,具体取决于它所做的操作

性能不需要太多的关注,特别是因为这不是一个用户进程


提示:先更新,然后插入。否则,当您执行第一次加载时,您将为导入的每一行获得一条插入记录和一条更新记录

输出
子句允许选择列表。虽然这不允许多个结果集,但它允许一个结果集处理所有操作

<output_clause>::=
{
    [ OUTPUT <dml_select_list> INTO { @table_variable | output_table }
        [ (column_list) ] ]
    [ OUTPUT <dml_select_list> ]
}
您将得到如下结果集:

| MergeAction | rowId | col1 | col2 |
| INSERT      | 3     | 1    | new  |
| UPDATE      | 1     | 2    | foo  |
| DELETE      | 2     | 3    | bar  |

是的,我在MSDN上看到了这一点,但希望能有一个黑客来克服这个限制。无论如何,谢谢你指出这一点!我想补充一点,您需要在输出之前先输入输出(正如语法括号所示)。我提到这一点只是为了防止有人两者的顺序都不正确,并且没有意识到为什么这对他们不起作用。可以将
MERGE
包装到存储过程中,并使用
INSERT。。。EXEC
将第二个
输出的结果插入到第二个表中,如我在回答中所示。它有其缺点,但在某些情况下可能有用。避免EXEC和INSERT之间的中间临时表的“正常”方法是将代码转换为一个内嵌的表值函数。不幸的是,这些都不允许有副作用(比如插入!),但是,如果您愿意编写一个流式C#SQL CLR,您可以绕过它!这是一条很长的路,但一定要走!如何区分在@MergeResults中插入/更新?
| MergeAction | rowId | col1 | col2 |
| INSERT      | 3     | 1    | new  |
| UPDATE      | 1     | 2    | foo  |
| DELETE      | 2     | 3    | bar  |