【问题标题】:VB.Net INSERT using a transaction & re-use the Last INSERTED IDVB.Net INSERT 使用事务并重新使用 Last INSERTED ID
【发布时间】:2014-08-06 07:40:04
【问题描述】:

我正在尝试在 VB.Net 中使用 SqlTransaction 对两个表执行插入操作,我想将第一个表中最后插入的 ID 插入到第二个表的列中。

我想使用OUTPUT INSERTED.ID 而不是@SCOPE_IDENTITY()

这是从 SQL Server Profiler 中提取的两个查询:

INSERT INTO USER(USER_NAME) 
OUTPUT INSERTED.USER_ID 
VALUES (@USER_NAME)

INSERT INTO USER_ADDRESS(USER_ID, USER_ADDRESS) 
VALUES ('', GETDATE(), ''001'', @OPD_OVP_NO, @OPD_PAT_CODE, @OPD_DATE, @OPD_AMOUNT)

这是 VB.Net 代码:

    Dim sqlTransaction As SqlTransaction= sqlConnection.BeginTransaction
    Dim sqlCommand As New SqlCommand With {.Connection = sqlConnection}
    sqlCommand.CommandText = "INSERT INTO USER(USER_NAME) OUTPUT INSERTED.USER_ID VALUES (@USER_NAME)"
    sqlCommand.Parameters.AddWithValue("@USER_NAME", "ABC")
    sqlCommand.Transaction = sqlTransaction
    sqlCommand.ExecuteNonQuery()

    sqlCommand.Parameters.Clear()
    sqlCommand.CommandText = "INSERT INTO USER_ADDRESS(USER_ID,USER_ADDRESS)VALUES(@LASTID, @USER_ADDRESS)"
    sqlCommand.Parameters.AddWithValue("@LASTID", LASTID)'//LAST ID should be from the previously inserted ID
    sqlCommand.Parameters.AddWithValue("@USER_ADDRESS","AB Street")
    sqlCommand.Transaction = sqlTransaction
    sqlCommand.ExecuteNonQuery()

    sqlTransaction.Commit()

我检查了其他线程,但它们只显示了如何从 @SCOPE_IDENTITY()OUTPUT INSERTED.USER_ID 获取最后插入的 ID,但没有说明如何将该值重新用于另一个插入语句。

【问题讨论】:

  • 在这种情况下,由于您使用用户输入作为 Id,最佳实践可能是包含一个日期时间列作为 InputDate,可用于重复使用。否则,您将需要选择插入的值,例如 select User_id from .. where user_name = 'ABC'
  • @GSerg 您建议使用单个 ExecuteNonQuery() 的线程上的答案,但我希望每个查询在事务中单独运行。
  • @GSerg 原因是因为我正在动态构建查询并且我不希望 @@params 混淆。
  • 那么你应该阅读ExecuteNonQuery vs ExecuteScalar

标签: sql sql-server vb.net


【解决方案1】:

您不能直接将第一个插入语句的 INSERTED.ID 用于第二个语句。

您应该首先使用 OUTPUT INTO 将其存储在临时表中。

DECLARE @MyTableVar table(USER_ID int);
DECLARE @NewUserID int;

INSERT INTO USER(USER_NAME)
OUTPUT INSERTED.USER_ID INTO @MyTableVar
VALUES (@USER_NAME);

SET @NewUserID = (SELECT USER_ID FROM @MyTableVar);

INSERT INTO USER_ADDRESS(USER_ID, USER_ADDRESS)
VALUES(@NewUserID, @USER_ADDRESS);

【讨论】:

    【解决方案2】:

    您可以编写一个执行两个插入的复合语句:

    create table [User] (User_ID int identity(97,-1) not null,
                         User_Name varchar(19) not null)
    create table User_Address (User_ID int not null,
                               User_Address varchar(22) not null)
    
    declare @User_Name varchar(19)
    declare @User_Address varchar(22)
    
    select @User_Name = 'abc', @User_Address='def'
    
    insert into User_Address (User_ID,User_Address)
    select User_ID,@User_Address
    from (
            insert into [User] (User_Name)
            output inserted.User_ID
            select @User_Name
        ) t
    
    select * from [User]
    select * from User_Address
    

    结果:

    User_ID     User_Name
    ----------- -------------------
    97          abc
    
    User_ID     User_Address
    ----------- ----------------------
    97          def
    

    【讨论】:

    • 为什么要嵌套selectinsert into User(User_Name) output inserted.User_ID, @User_Address into UserAddress(User_ID,User_Address) values(@User_Name)
    【解决方案3】:

    处理这类事情的最佳方法是在 SQL 存储过程中执行事务,而不是使用客户端控制的事务。存储过程将能够访问使用第一个插入的 ID 并在第二个插入中使用它,而不会使返回给客户端的输出参数复杂化。此外,您的数据库将扩展得更好,因为它将使事务持续时间尽可能短..

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-22
      • 2020-11-20
      • 1970-01-01
      • 1970-01-01
      • 2021-11-24
      • 2012-04-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多