关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » SQL Server »如何SQL Server中准确的获得标识值(1)

    如何SQL Server中准确的获得标识值(1)

    2015-10-04 00:00:00 出处:ITJS
    分享

    SQL Server有三种不同的函数可以用来获得含有标识列的表里最后生成的标识值:

    @@IDENTITY   SCOPE_IDENTITY()   IDENT_CURRENT('数据表名') 

    以上三个函数虽然都可以返回数据库引擎最后生成插入标识列的值,但是根据插入行的来源(例如:存储过程或触发器)以及插入该行的连接不同,这三个函数在功能上也有所不同。

    @@IDENTITY函数可以返回所有范围内当前连接插入最后所生成的标识值(包括任何调用的存储过程和触发器)。这个函数不止可以适用于表。函数返回的值是最后表插入行生成的标识值。

    SCOPE_IDENTITY()函数跟上一个函数几乎是一摸一样的,不同的地方:即前者返回的值只限于当前范围(即执行中的存储过程)。

    最后是IDENT_CURRENT函数,它可以用于所有范围和所有连接,获得最后生成的表标识值。跟前面两个函数不同的是,这个函数只用于表,并且使用[数据表名]作为一个参数。

    我们可以举实例来演示上述函数是如何运作的。

    首先,我们创建两个简单的例表:一个代表客户表,一个代表审计表。创建审计表的目的是为了跟踪数据库里插入和删除信息的所有记录。

    以下是引用片段:

    CREATE TABLE dbo.customer   (customerid INT IDENTITY(1,1) PRIMARY KEY)   GO   CREATE TABLE dbo.auditlog   (auditlogid INT IDENTITY(1,1) PRIMARY KEY,   customerid INT, action CHAR(1),   changedate datetime DEFAULT GETDATE())   GO 

    然后,我们还要创建一个存储过程和一个辅助触发器,这个存储过程将在数据库表里插入新的客户行,并返回生成的标识值,而触发器则会向审计表插入行:

    以下是引用片段:

    CREATE PROCEDURE dbo.p_InsertCustomer @customerid INT output   AS   SET nocount ON   INSERT INTO dbo.customer DEFAULT VALUES   SELECT @customerid = @@identity   GO   CREATE TRIGGER dbo.tr_customer_log ON dbo.customer   FOR INSERT, DELETE   AS   IF EXISTS (SELECT 'x' FROM inserted)   INSERT INTO dbo.auditlog (customerid, action)   SELECT customerid, 'I'   FROM inserted   ELSE   IF EXISTS (SELECT 'x' FROM deleted)   INSERT INTO dbo.auditlog (customerid, action)   SELECT customerid, 'D'   FROM deleted   GO 

    现在我们可以执行程序,创建客户表的第一行了,以下是引用片段:

    DECLARE @customerid INT   EXEC dbo.p_InsertCustomer @customerid output   SELECT @customerid AS customerid 

    执行后返回了我们需要的第一个客户的值,并记录了插入审计表的条目。到目前为止,数据显示没有任何问题。

    假设由于先前沟通出现了偏差,一个客户服务代表现在需要从数据库里删除掉这个新增的客户。我们现在就来把新插入的客户行删除掉:

    以下是引用片段:

    DELETE FROM dbo.customer WHERE customerid = 1 

    现在,客户工作表为空表,而审计工作表里则有两行——第一行是记录第一次插入行,第二行是记录删除客户记录。

    现在我们再往数据库里增加第二个客户信息并检测一下获得的标识值:

    以下是引用片段:

    DECLARE @customerid INT   EXEC dbo.p_InsertCustomer @customerid output   SELECT @customerid AS customerid 

    哇!看看出现了什么情况!假如我们现在再看客户工作表,就会发现虽然创建了客户2,但是我们的程序返回的标识值为3!到底出了什么问题呢 回想一下,前面讲过@@IDENTITY函数的作用范围,它会返回主程序调用的任何存储过程或触动任何触发器最后生成的标识值,取决于哪一个在函数被调用前最后生成标识值。在我们的例子里,初始范围是p_InsertCustomer,然后是触发器用来记录插入条目的tr_customer_log。因此我们返回获得的标识值是审计工作表里触发器插入生成的标识值,而不是我们想要的客户工作表里的生成的标识值。

    在SQL Server 2000之前的版本,@@IDENTITY函数是获得标识值的唯一方法。由于会出现这样的存储过程/触发器问题,SQL Server开发团队在SQL Server 2000中引入了 SCOPE_IDENTITY()和IDENT_CURRENT这两个函数来解决这个问题。所以在旧的SQL Server版本里,要解决这个问题比较麻烦。假如是SQL Server6.5版本,我建议可以去掉标识列,然后创建一个可以包含下一个需要使用的值的辅助表,可以达到标识列的作用效果。不过这个办法也不是什么高明的办法。

    现在我们来修改一下存储过程来使用SCOPE_IDENTITY()函数,并重新执行程序来添加第三个客户条目:

    以下是引用片段:

    ALTER PROCEDURE dbo.p_InsertCustomer @customerid INT output   AS   SET nocount ON   INSERT INTO dbo.customer DEFAULT VALUES   SELECT @customerid = SCOPE_IDENTITY()   GO   DECLARE @customerid INT   EXEC dbo.p_InsertCustomer @customerid output   SELECT @customerid AS customerid 

    我们返回的标识值还是3,不过这次我们获得的标识值是正确的,因为我们添加了第三个客户条目。假如我们检查一下审计工作表,就会发现里面已经有第四个条目记录新插入的客户记录。由于函数SCOPE_IDENTITY()只作用于当前范围,只返回当前执行程序的值,这样就避免了发生刚才那样的问题。

    前面讲过,函数@@IDENTITY和函数SCOPE_IDENTITY()不止用于表,不像函数IDENT_CURRENT那样可以用表作为参数。使用@@IDENTITY和SCOPE_IDENTITY()这两个函数的话在设置代码时需要加倍小心,才能够从所需要的表里获得正确的标识值。从表面上来看,放弃这两个函数,只使用函数IDENT_CURRENT并指定表是更安全的办法。这样可以避免出现获得错误标识值的情况,对吧 记得先前说过函数IDENT_CURRENT不仅会跨范围,而且它还会跨连接。也就是说,使用这个函数生成的值不仅仅限于你的连接所执行的程序,它的涵盖范围还包括整个数据库所有的连接。因此,即使是在规模较小的OLTP环境里,它也会出现不能准确返回所需值的问题。这样就可能发生类似前面@@IDENTITY函数/触发器的数据损坏问题。

    我的建议是函数SCOPE_IDENTITY()是三个函数里最安全的函数,应该设置为默认函数。使用这个函数,你可以放心地添加触发器和次存储过程,无需担心意外损坏数据。而另外两个函数可以保留应付特殊的情况,当遇到需要使用这两个函数的特殊情况时,建议记录它们的使用情况并进行测试。

    小技巧:

    Sql Server 判断表是存在标识列

    If Exists(Select * from SysColumns Where ID=OBJECT_ID(N'TEST1') And COLUMNPROPERTY(ID,Name,'IsIdentity')=1)

    Print N'有自增列'

    Else

    Print N'没有自增列'

    Sql Server 显示当前数据库包含自增列的表

    Select b.name,a.* from SysColumns a,sysobjects b Where a.id=b.id and COLUMNPROPERTY(a.ID,a.Name,'IsIdentity')=1

    SQL SERVER自增张字段复位方法:

    SQLSERVER 复位:

    Truncate table Ashare_CJHB

    Dbcc checkident (Ashare_CJHB,RESEED,0)

    SQL Server有三种不同的函数可以用来获得含有标识列的表里最后生成的标识值:

    @@IDENTITY   SCOPE_IDENTITY()   IDENT_CURRENT('数据表名') 

    以上三个函数虽然都可以返回数据库引擎最后生成插入标识列的值,但是根据插入行的来源(例如:存储过程或触发器)以及插入该行的连接不同,这三个函数在功能上也有所不同。

    @@IDENTITY函数可以返回所有范围内当前连接插入最后所生成的标识值(包括任何调用的存储过程和触发器)。这个函数不止可以适用于表。函数返回的值是最后表插入行生成的标识值。

    SCOPE_IDENTITY()函数跟上一个函数几乎是一摸一样的,不同的地方:即前者返回的值只限于当前范围(即执行中的存储过程)。

    最后是IDENT_CURRENT函数,它可以用于所有范围和所有连接,获得最后生成的表标识值。跟前面两个函数不同的是,这个函数只用于表,并且使用[数据表名]作为一个参数。

    我们可以举实例来演示上述函数是如何运作的。

    首先,我们创建两个简单的例表:一个代表客户表,一个代表审计表。创建审计表的目的是为了跟踪数据库里插入和删除信息的所有记录。

    以下是引用片段:

    CREATE TABLE dbo.customer   (customerid INT IDENTITY(1,1) PRIMARY KEY)   GO   CREATE TABLE dbo.auditlog   (auditlogid INT IDENTITY(1,1) PRIMARY KEY,   customerid INT, action CHAR(1),   changedate datetime DEFAULT GETDATE())   GO 

    然后,我们还要创建一个存储过程和一个辅助触发器,这个存储过程将在数据库表里插入新的客户行,并返回生成的标识值,而触发器则会向审计表插入行:

    以下是引用片段:

    CREATE PROCEDURE dbo.p_InsertCustomer @customerid INT output   AS   SET nocount ON   INSERT INTO dbo.customer DEFAULT VALUES   SELECT @customerid = @@identity   GO   CREATE TRIGGER dbo.tr_customer_log ON dbo.customer   FOR INSERT, DELETE   AS   IF EXISTS (SELECT 'x' FROM inserted)   INSERT INTO dbo.auditlog (customerid, action)   SELECT customerid, 'I'   FROM inserted   ELSE   IF EXISTS (SELECT 'x' FROM deleted)   INSERT INTO dbo.auditlog (customerid, action)   SELECT customerid, 'D'   FROM deleted   GO 

    现在我们可以执行程序,创建客户表的第一行了,以下是引用片段:

    DECLARE @customerid INT   EXEC dbo.p_InsertCustomer @customerid output   SELECT @customerid AS customerid 

    执行后返回了我们需要的第一个客户的值,并记录了插入审计表的条目。到目前为止,数据显示没有任何问题。

    假设由于先前沟通出现了偏差,一个客户服务代表现在需要从数据库里删除掉这个新增的客户。我们现在就来把新插入的客户行删除掉:

    以下是引用片段:

    DELETE FROM dbo.customer WHERE customerid = 1 

    现在,客户工作表为空表,而审计工作表里则有两行——第一行是记录第一次插入行,第二行是记录删除客户记录。

    现在我们再往数据库里增加第二个客户信息并检测一下获得的标识值:

    以下是引用片段:

    DECLARE @customerid INT   EXEC dbo.p_InsertCustomer @customerid output   SELECT @customerid AS customerid 

    哇!看看出现了什么情况!假如我们现在再看客户工作表,就会发现虽然创建了客户2,但是我们的程序返回的标识值为3!到底出了什么问题呢 回想一下,前面讲过@@IDENTITY函数的作用范围,它会返回主程序调用的任何存储过程或触动任何触发器最后生成的标识值,取决于哪一个在函数被调用前最后生成标识值。在我们的例子里,初始范围是p_InsertCustomer,然后是触发器用来记录插入条目的tr_customer_log。因此我们返回获得的标识值是审计工作表里触发器插入生成的标识值,而不是我们想要的客户工作表里的生成的标识值。

    在SQL Server 2000之前的版本,@@IDENTITY函数是获得标识值的唯一方法。由于会出现这样的存储过程/触发器问题,SQL Server开发团队在SQL Server 2000中引入了 SCOPE_IDENTITY()和IDENT_CURRENT这两个函数来解决这个问题。所以在旧的SQL Server版本里,要解决这个问题比较麻烦。假如是SQL Server6.5版本,我建议可以去掉标识列,然后创建一个可以包含下一个需要使用的值的辅助表,可以达到标识列的作用效果。不过这个办法也不是什么高明的办法。

    现在我们来修改一下存储过程来使用SCOPE_IDENTITY()函数,并重新执行程序来添加第三个客户条目:

    以下是引用片段:

    ALTER PROCEDURE dbo.p_InsertCustomer @customerid INT output   AS   SET nocount ON   INSERT INTO dbo.customer DEFAULT VALUES   SELECT @customerid = SCOPE_IDENTITY()   GO   DECLARE @customerid INT   EXEC dbo.p_InsertCustomer @customerid output   SELECT @customerid AS customerid 

    我们返回的标识值还是3,不过这次我们获得的标识值是正确的,因为我们添加了第三个客户条目。假如我们检查一下审计工作表,就会发现里面已经有第四个条目记录新插入的客户记录。由于函数SCOPE_IDENTITY()只作用于当前范围,只返回当前执行程序的值,这样就避免了发生刚才那样的问题。

    前面讲过,函数@@IDENTITY和函数SCOPE_IDENTITY()不止用于表,不像函数IDENT_CURRENT那样可以用表作为参数。使用@@IDENTITY和SCOPE_IDENTITY()这两个函数的话在设置代码时需要加倍小心,才能够从所需要的表里获得正确的标识值。从表面上来看,放弃这两个函数,只使用函数IDENT_CURRENT并指定表是更安全的办法。这样可以避免出现获得错误标识值的情况,对吧 记得先前说过函数IDENT_CURRENT不仅会跨范围,而且它还会跨连接。也就是说,使用这个函数生成的值不仅仅限于你的连接所执行的程序,它的涵盖范围还包括整个数据库所有的连接。因此,即使是在规模较小的OLTP环境里,它也会出现不能准确返回所需值的问题。这样就可能发生类似前面@@IDENTITY函数/触发器的数据损坏问题。

    我的建议是函数SCOPE_IDENTITY()是三个函数里最安全的函数,应该设置为默认函数。使用这个函数,你可以放心地添加触发器和次存储过程,无需担心意外损坏数据。而另外两个函数可以保留应付特殊的情况,当遇到需要使用这两个函数的特殊情况时,建议记录它们的使用情况并进行测试。

    小技巧:

    Sql Server 判断表是存在标识列

    If Exists(Select * from SysColumns Where ID=OBJECT_ID(N'TEST1') And COLUMNPROPERTY(ID,Name,'IsIdentity')=1)

    Print N'有自增列'

    Else

    Print N'没有自增列'

    Sql Server 显示当前数据库包含自增列的表

    Select b.name,a.* from SysColumns a,sysobjects b Where a.id=b.id and COLUMNPROPERTY(a.ID,a.Name,'IsIdentity')=1

    SQL SERVER自增张字段复位方法:

    SQLSERVER 复位:

    Truncate table Ashare_CJHB

    Dbcc checkident (Ashare_CJHB,RESEED,0)

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    Destoon 模板存放规则及语法参考

    Destoon系统常量与变量

    Destoon系统目录文件结构说明

    Destoon 系统安装指南

    Destoon会员公司主页模板风格添加方法

    Destoon 二次开发入门

    Microsoft 将于 2026 年 10 月终止对 Windows 11 SE 的支持

    Windows 11 存储感知如何设置?了解Windows 11 存储感知开启的好处

    Windows 11 24H2 更新灾难:系统升级了,SSD固态盘不见了...

    小米路由器买哪款?Miwifi热门路由器型号对比分析

    IT头条

    Synology 对 Office 套件进行重大 AI 更新,增强私有云的生产力和安全性

    01:43

    StorONE 的高效平台将 Storage Guardian 数据中心占用空间减少 80%

    11:03

    年赚千亿的印度能源巨头Nayara 云服务瘫痪,被微软卡了一下脖子

    12:54

    国产6nm GPU新突破!砺算科技官宣:自研TrueGPU架构7月26日发布

    01:57

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    技术热点

    最全面的前端开发指南

    Windows7任务栏桌面下角的一些正在运行的图标不见了

    sql server快速删除记录方法

    SQL Server 7移动数据的6种方法

    SQL Server 2008的新压缩特性

    每个Java程序员必须知道的5个JVM命令行标志

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。