禅道SQL Server自增ID问题
禅道SQL Server自增ID问题
分页改完以后,又遇到一个问题:新增数据成功了,但后面拿自增 ID 的地方不对。
MySQL 里常见是 AUTO_INCREMENT,插入后用 LAST_INSERT_ID() 或驱动里的 lastInsertId。SQL Server 里是 IDENTITY,取法不一样。
MySQL 写法
MySQL 建表大概这样:
1 | CREATE TABLE zt_demo ( |
插入:
1 | INSERT INTO zt_demo(name) VALUES ('test'); |
SQL Server 写法
SQL Server 自增列用 IDENTITY:
1 | CREATE TABLE dbo.zt_demo ( |
IDENTITY(1,1) 的意思是:
1 | 从1开始,每次加1 |
插入:
1 | INSERT INTO dbo.zt_demo(name) VALUES (N'test'); |
取刚插入的 ID:
1 | SELECT SCOPE_IDENTITY() AS id; |
不要乱用 @@IDENTITY
SQL Server 里还有:
1 | SELECT @@IDENTITY; |
但这个容易受触发器影响。比如插入 A 表时触发器又插入了 B 表,@@IDENTITY 可能拿到 B 表的 identity。
所以业务里一般用:
1 | SELECT SCOPE_IDENTITY(); |
更稳一点。
OUTPUT INSERTED.id
如果想在插入时直接拿 ID,也可以用 OUTPUT:
1 | INSERT INTO dbo.zt_demo(name) |
批量插入时也能返回多行:
1 | INSERT INTO dbo.zt_demo(name) |
这个在改批量导入时比较好用。
PDO 里要注意
如果 PHP 里原来直接依赖 MySQL 的 lastInsertId,切到 SQL Server 后要实际测一下。
当时我更愿意在 SQL 里显式补:
1 | INSERT INTO dbo.zt_demo(name) VALUES (?); |
然后在代码里取结果。
不要想当然认为所有 PDO 驱动表现一样。
临时插入指定 ID
有些初始化脚本需要插入固定 id。SQL Server 默认不允许直接插 identity 列,需要打开:
1 | SET IDENTITY_INSERT dbo.zt_demo ON; |
注意同一时间一个 session 只能对一张表开 IDENTITY_INSERT。
小结
这块改造时主要记住:
- MySQL 是
AUTO_INCREMENT,SQL Server 是IDENTITY。 - SQL Server 取当前插入 ID 优先用
SCOPE_IDENTITY()或OUTPUT INSERTED.id。 - 不要随便用
@@IDENTITY。 - 初始化固定 ID 时才考虑
IDENTITY_INSERT。 - 批量插入拿 ID,用
OUTPUT比一条条查更清楚。
参考
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 无尽infinite!

