【问题标题】:Whats the best way to update a single record via SQL and obtain the id of the record that was updated? (Java/MSSQL)通过 SQL 更新单个记录并获取更新记录的 id 的最佳方法是什么? (Java/MSSQL)
【发布时间】:2008-12-09 13:17:21
【问题描述】:

我知道我可以像这样更新单个记录 - 但是如何访问已更新记录的 ID? (我使用的是 MSSQL,所以不能使用 Oracles RowId)

update myTable
set myCol = 'foo'
where itemId in (select top 1 itemId from myTable )

如果我正在执行插入,我可以使用 getGeneratedKeys 来获取 id 字段值,但我认为没有等效的更新?

我知道我可以使用可滚动的结果集来做我想做的事

stmt = conn.prepareStatement("select top 1 myCol, itemId from myTable", ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
ResultSet resultSet = stmt.executeQuery();
if(resultSet.first()){
    resultSet.updateString(1, "foo");
    resultSet.updateRow();
    String theItemId = resultSet.getString(1)
}
resultSet.close();

但我担心性能,因为测试显示负载下的锁定超时,我想知道是否有更好/更简单的方法?

-- 编辑: 只是为了解决这个问题... 当我们迁移到 MSSQL2005 时,我们将升级我们的代码以使用 Rich 的答案。 在当前版本中,我们使用了锁提示:(UPDLOCK ROWLOCK READPAST) 来缓解原始代码显示的性能问题。

【问题讨论】:

    标签: java sql-server


    【解决方案1】:

    此示例在 MSSQL 2005 中运行良好...

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    DROP TABLE [dbo].[TEST_TABLE]
    GO
    
    CREATE TABLE [dbo].[TEST_TABLE](
        [id] [int] IDENTITY(1,1) NOT NULL,
        [name] [nvarchar](100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
     CONSTRAINT [PK_TEST_TABLE] 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]
    
    
    -- An insert which will return the identity
    INSERT INTO [dbo].[TEST_TABLE] ([name]) 
    OUTPUT inserted.id
    VALUES('Test 1')
    
    -- Another insert which will return the identity
    INSERT INTO [dbo].[TEST_TABLE] ([name]) 
    OUTPUT inserted.id
    VALUES('Test 2')
    
    -- Now an update which will return the identity
    UPDATE [dbo].[TEST_TABLE]
    SET [name] = 'Updated Test 1'
    OUTPUT inserted.id
    WHERE [name] = 'Test 1'
    
    SELECT id, [name] FROM [dbo].[TEST_TABLE]
    

    更具体地说是您的查询...

    update myTable
    set myCol = 'foo'
    output inserted.itemid
    where itemId in (select top 1 itemId from myTable )
    

    【讨论】:

    • 如果你想捕获脚本中的值(例如,返回它而不是作为结果集输出)创建一个本地表变量(“declare @output table (itemid int) ") 并执行“将插入的.itemid 输出到@output”。然后您可以从那里选择它以供进一步使用。
    • 这个例子正是我所追求的……我目前停留在 MSSQL 2000 上,但 2008 年的迁移计划在 3 月进行,所以我会暂时保留这个。谢谢
    • 我很难理解为什么我被否决了,评论会有所帮助
    【解决方案2】:

    我会做以下事情:

    Begin Tran
    
    update myTable
    set myCol = 'foo'
    where itemId in (select top 1 itemId from myTable )
    
    select top 1 itemId from myTable
    
    Commit Tran
    

    【讨论】:

      【解决方案3】:

      这必须在一个语句中吗?最终这将是最好的存储过程

      Create Procedure doMyUpdate
      
       @Id int output
      
      as
      
      Set @Id = (select top 1 itemId from myTable)
      update myTable
      set myCol = 'foo'
      where itemId = @Id
      

      另一种方法是使用 th RETURN 关键字和内置的 RETURN_VALUE 参数...

      Create Procedure doMyUpdate
      
      as
      
      Declare @Id int
      Set @Id = (select top 1 itemId from myTable)
      
      update myTable
      set myCol = 'foo'
      where itemId = @Id
      
      RETURN @Id
      

      【讨论】:

      • 它不必在单个语句中。但它需要在多线程环境中工作。也许诀窍是创建一个唯一键并将其用作我的更新语句的一部分(即到一个新列)。然后我可以使用 myUniqueCol = 'bar35636' 进行选择?
      【解决方案4】:

      对于插入 MSQSQL 服务器具有 @@Identity 参数,该参数具有最后插入记录的 ID。

      【讨论】:

      • 已弃用,使用 scope_identity()
      • 并且也不适用于更新 - 这是最后一个值插入。 @@Identity 也有一个缺点,如果在其他地方发生了插入新身份的其他事件,您将得到那个而不是您想要的。
      猜你喜欢
      • 1970-01-01
      • 2013-12-17
      • 1970-01-01
      • 2016-10-15
      • 2017-07-27
      • 2011-06-05
      • 1970-01-01
      • 2017-01-14
      • 1970-01-01
      相关资源
      最近更新 更多