output必须嵌入insert语句中,不可单独执行;正确语法为insert...output...values/select;多行插入时返回结果集,需用表变量承接,不能直接赋值给标量变量。

OUTPUT子句必须配合INSERT语句一起用,不能单独执行
很多人试过先写 INSERT,再写 OUTPUT,结果报错“Incorrect syntax near the keyword 'OUTPUT'”。这是因为 OUTPUT 是 INSERT 的一部分,不是独立语句。它必须紧跟在 VALUES 或 SELECT 后面,中间不能换行或加分号隔开。
常见错误写法:INSERT INTO users (name) VALUES ('Alice');OUTPUT INSERTED.id; ← 这会直接报错
正确写法是:INSERT INTO users (name) OUTPUT INSERTED.id VALUES ('Alice');
-
OUTPUT必须紧接在VALUES或SELECT前(顺序不能颠倒) - 如果表有触发器,
OUTPUT仍能正常返回,但触发器里的修改不会反映在INSERTED中 - 不能对视图或远程表使用
OUTPUT返回自增列(除非视图底层映射的是单个本地表且 IDENTITY 属性明确)
INSERTED.id 要求目标列确实是 IDENTITY 列,且未被显式插入
如果建表时用了 IDENTITY(1,1),但你在 INSERT 里手动指定了 id 值(比如 SET IDENTITY_INSERT users ON 后插入),那 OUTPUT INSERTED.id 返回的就是你写的值,不是数据库生成的自增值——这容易误判为“没拿到新ID”。
更隐蔽的问题:某些 ORM 或迁移脚本可能把列定义成 INT NOT NULL + 默认约束,而非 IDENTITY。这种情况下 INSERTED.id 依然存在,但值来自默认值(如 DEFAULT 或序列),不是自增逻辑,OUTPUT 不会报错,但语义已不同。
- 确认方式:查
sys.columns.is_identity = 1,别只看列名叫id - 如果用了序列(
SEQUENCE)+DEFAULT,得用OUTPUT INSERTED.id,但返回值不具“自增原子性”,并发时可能跳号 -
OUTPUT中的INSERTED是只读伪表,不能加WHERE或JOIN,也不能引用其他表别名
多行插入时 OUTPUT 返回结果集,不是单个值
执行 INSERT INTO logs (msg) OUTPUT INSERTED.id VALUES ('a'),('b'),('c');,结果是三行 id 的结果集,不是标量。如果你在存储过程中想把它存进变量,会报错“Subquery returned more than 1 value”。
要取单个值(比如只想要第一条),得用临时表或表变量承接:
DECLARE @new_ids TABLE (id INT);
INSERT INTO logs (msg)
OUTPUT INSERTED.id INTO @new_ids
VALUES ('a'), ('b'), ('c');
SELECT TOP 1 id FROM @new_ids;
- 用
INTO子句把OUTPUT结果写入表变量,是最稳妥的多行处理方式 - 不要试图用
SELECT @var = INSERTED.id——INSERTED在OUTPUT中不可直接赋值给变量 - 如果只插一行,且确定无并发风险,可直接用
SELECT SCOPE_IDENTITY()替代,但它和OUTPUT的事务可见性一致,性能差异微乎其微
SQL Server 2022 没新增 OUTPUT 语法,但要注意兼容级别影响
SQL Server 2022 默认兼容级别是 160,OUTPUT 行为与 2019/2017 完全一致。但如果你把数据库兼容级别降到了 110(SQL Server 2012)以下,OUTPUT 仍可用,只是不支持某些高级用法,比如 OUTPUT INTO 写入分区表或内存优化表(需 130+)。
真正容易被忽略的点是:如果数据库启用了 ACCELERATED_DATABASE_RECOVERY = ON(2022 默认开启),OUTPUT 返回的 INSERTED 数据仍是事务内最新状态,不受 ADR 日志截断影响——这点和旧版本一致,但有人误以为 ADR 会改变 OUTPUT 行为。
- 检查兼容级别:
SELECT compatibility_level FROM sys.databases WHERE name = DB_NAME(); - 不要为了用
OUTPUT去调低兼容级别;也不必为 2022 升级专门改写已有OUTPUT逻辑 - 如果表是内存优化的,
OUTPUT只支持INTO,不支持直接返回结果集(会报错Msg 10794)
OUTPUT 必须嵌在 INSERT 里,或者在多行场景下硬要塞进变量。留个心眼:只要看到“返回刚插入的ID”,第一反应就该是“我是不是在拿结果集当标量用”。










