不能。SQL Server原生OUTPUT子句仅支持返回每行的列值、常量或表达式,不支持COUNT(*)、SUM()等需全集计算的聚合函数;必须借助表变量捕获后聚合,或单行场景下用子查询配合OUTPUT。

SQL Server中OUTPUT子句能否直接返回聚合值?
不能。原生OUTPUT子句只能返回被插入行的列值(包括INSERTED.*)、常量或表达式,但不支持COUNT(*)、SUM()这类运行时聚合——因为OUTPUT在每一行插入时触发,而聚合需等整个语句执行完才可计算。
如何在Insert后立刻拿到行数、最大ID等聚合信息?
最稳妥的做法是组合使用OUTPUT + 表变量 + 聚合查询。关键在于把OUTPUT INTO @table_var作为“中间捕获层”,再对表变量做聚合:
DECLARE @InsertedRows TABLE (id INT, amount DECIMAL(10,2)); INSERT INTO orders (customer_id, amount, created_at) OUTPUT INSERTED.id, INSERTED.amount INTO @InsertedRows VALUES (101, 299.99, GETDATE()), (102, 149.50, GETDATE()), (101, 89.00, GETDATE()); SELECT COUNT(*) AS row_count, MAX(id) AS max_id, SUM(amount) AS total_amount FROM @InsertedRows;
-
@InsertedRows必须显式声明列类型,且与OUTPUT列出的字段严格匹配 - 若只关心行数,用
@@ROWCOUNT更轻量;但需要具体数据(如新生成的id)或分组聚合时,表变量是唯一可靠路径 - 注意:不能在
OUTPUT INTO中引用临时表(#temp),只支持表变量或永久表
想返回自增ID和统计结果,但又不想用表变量?
可以改用OUTPUT + SELECT嵌套,但仅适用于单行或需逐行处理的场景。例如插入一行并返回ID及当前表总行数:
INSERT INTO logs (message, level)
OUTPUT INSERTED.id, (SELECT COUNT(*) FROM logs) AS total_logs
VALUES ('System started', 'INFO');
- 这种写法里,子查询
(SELECT COUNT(*) FROM logs)在INSERT提交后执行,所以能反映“含本次插入”的最新总数 - 但多行插入时,该子查询对每行都重复执行,性能差,且结果冗余(每行都返回相同总数)
- 不推荐用于批量插入;仅当明确只需单行+全局聚合且并发低时可考虑
容易忽略的事务与并发问题
OUTPUT INTO @table_var本身不加锁,但整个INSERT语句仍受事务隔离级别约束。真正危险的是:如果在高并发下依赖MAX(id)推断“最后插入的ID”,可能出错——因为其他会话可能同时插入并提交,导致@InsertedRows里的MAX(id)并非全局最新。
- 若业务逻辑依赖“刚插入的最大ID”做后续关联,应改用
SCOPE_IDENTITY()(仅限单行)或OUTPUT INSERTED.id捕获全部ID再取MAX() - 不要在
OUTPUT子句里调用用户定义函数(UDF),尤其是含副作用的,行为不可预测 - XML格式输出或大字段(
TEXT/IMAGE已弃用,但VARCHAR(MAX)仍要注意)可能导致内存压力,测试时需关注执行计划中的CONVERT_IMPLICIT警告










