zoukankan      html  css  js  c++  java
  • SQLServer获取插入记录的主键值的四种方式与测试比较

    概念释义

    会话(Session):当客户端应用程序连接到SQL Server时,双方建立一个“会话”来交换信息。严格地说,会话与底层物理连接不同,它是连接的SQL Server逻辑表示。比如说,在 SQL Server Management Studio 新建一个查询、打开了一个对话框,即表示新建了一个”会话“;在代码中使用 SqlConnection,new了一个连接,即表示新建了一个”会话“。

    作用域(Scope): 是一个模块:存储过程、触发器、函数或批处理。因此,如果两条语句位于相同的存储过程、函数或批处理中,则它们处于相同的作用域。

    一、所有方式

    方法 描述 作用域 会话
    SCOPE_IDENTITY() 返回在当前活动连接中的任何表的最后的ID 同一作用域 同一会话
    @@IDENTITY 返回在当前活动连接中的任何表的最后的ID 任何作用域 同一会话
    IDENT_CURRENT(table_name) 返回指定表的最后的ID 任何作用域 任何会话
    OUTPUT 子句 返回插入数据的任何指定的列信息(触发器必须禁用) / /

    二、使用示例

    2.1 应用场景

    有表 Tb1 及其两个 Insert 触发器(为了模拟“作用域”):Tr1、Tr1_2

    有表 Tb2 及其一个 Insert 触发器(为了模拟“作用域”):Tr2

    • Tb1
    CREATE TABLE [dbo].[Tb1](
    	[ID] [int] IDENTITY(1,1) NOT NULL,
    	[Name] [nvarchar](8) NULL,
     CONSTRAINT [PK_Tb1] PRIMARY KEY CLUSTERED 
    (
    	[ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    • Tr1:当 Tb1插入一条数据时,再向 Tb1 插入一条数据
    CREATE TRIGGER [dbo].[Tr1]
       ON  [dbo].[Tb1]
       AFTER INSERT
    AS 
    BEGIN
        declare @name sysname
    	select @name=Name from inserted
    	insert into dbo.Tb1(Name) values(@name+'byTr1');
    END
    
    • Tr1_2:当 Tb1 插入一条数据时,向 Tb2 插入一条数据
    CREATE TRIGGER [dbo].[Tr1_2]
       ON  [dbo].[Tb1]
       AFTER INSERT
    AS 
    BEGIN
        declare @name sysname
    	select @name=Name from inserted
    	insert into dbo.Tb2(Name) values(@name+'_byTr1_2');
    END
    

    • Tb2
    CREATE TABLE [dbo].[Tb2](
    	[ID] [int] IDENTITY(1,1) NOT NULL,
    	[Name] [nvarchar](8) NOT NULL,
     CONSTRAINT [PK_Tb2] PRIMARY KEY CLUSTERED 
    (
    	[ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    • Tr2
    CREATE TRIGGER [dbo].[Tr2]
       ON  [dbo].[Tb2]
       AFTER INSERT
    AS 
    BEGIN
        declare @name sysname
    	select @name=Name from inserted
    	insert into dbo.Tb2(Name) values(@name+'_byTr2');
    END
    

    2.2 测试方式

    注:Tb1 的触发器及代表了“作用域”,已包括在如下个测试过程中

    • 执行向 Tb1 插入一条数据,在同一会话中,分别使用三种方式(除output)获取插入记录的 ID
    insert into dbo.Tb1(Name) values('User1')
    
    select SCOPE_IDENTITY() as [SCOPE_IDENTITY]
    select @@IDENTITY as [@@IDENTITY]
    select IDENT_CURRENT('dbo.Tb1') as [IDENT_CURRENT('dbo.Tb1')]
    select IDENT_CURRENT('dbo.Tb2') as [IDENT_CURRENT('dbo.Tb2')]
    
    select ID as [Tb1.ID], Name as [Tb1.Name] from dbo.Tb1
    select ID as [Tb2.ID], Name as [Tb2.Name] from dbo.Tb2
    
    /*
    truncate table dbo.Tb1
    truncate table dbo.Tb2
    */
    

    输出:

    image

    • 执行向 Tb1 插入一条数据,在两个不同会话中,分别使用三种方式(除output)获取插入记录的 ID

    (使用程序模拟并发易实现)

    • 关闭 Tb1 触发器,执行向 Tb1、Tb2 分别插入一条数据,在同一会话中,分别使用四种方式获取插入记录的 ID
    insert into dbo.Tb1(Name) output inserted.ID as [Tb1.output inserted.ID] values('User1')
    insert into dbo.Tb2(Name) values('User2')
    
    select SCOPE_IDENTITY() as [SCOPE_IDENTITY()]
    select @@IDENTITY as [@@IDENTITY]
    select IDENT_CURRENT('dbo.Tb1') as [IDENT_CURRENT('dbo.Tb1')]
    select IDENT_CURRENT('dbo.Tb2') as [IDENT_CURRENT('dbo.Tb2')]
    
    select ID as [Tb1.ID], Name as [Tb1.Name] from dbo.Tb1
    select ID as [Tb2.ID], Name as [Tb2.Name] from dbo.Tb2
    
    /*
    truncate table dbo.Tb1
    truncate table dbo.Tb2
    */
    

    输出:

    image

    • 关闭 Tb1 触发器,执行向 Tb1、Tb2 分别插入一条数据,在两个不同会话中,分别使用 四种方式获取插入记录的 ID

    (使用程序模拟并发易实现)

    三、结论

    若获取当前首次插入的记录ID,推荐使用 SCOPE_IDENTITY()

  • 相关阅读:
    LuoguP1016 旅行家的预算 (贪心)
    LuoguP2254 [NOI2005]瑰丽华尔兹 (单调队列优化DP)(用记忆化过了。。。)
    LuoguP2876 [USACO07JAN]解决问题Problem Solving (区间DP)(未完成)
    Luogu3275 [SCOI2011]糖果 (差分约束)
    Luogu1993 小K的农场 (差分约束)
    Luogu4427 [BJOI2018]求和 (树上差分)
    LuoguP1516 青蛙的约会 (Exgcd)
    POJ3903Stock Exchange (LIS)
    LuoguP1020 导弹拦截 (LIS)
    线性筛
  • 原文地址:https://www.cnblogs.com/seanyan/p/15165711.html
Copyright © 2011-2022 走看看