【问题标题】:How to lock a row so that a select returns a row exactly once?如何锁定一行以便选择只返回一行?
【发布时间】:2016-03-24 01:49:34
【问题描述】:

这里是 SQL 业余爱好者。

我有一张包含优惠券代码的表格:

id  voucherCode  UserId
------------------------
1   abcde        13
2   bcdef        11
3   cdefg
4   defgh

现在,如果我的一位用户有资格获得优惠券代码,我会从我的桌子上得到一个:

SELECT TOP 1 * FROM tableName WHERE UserId IS NULL;
UPDATE tableName SET UserId = @UserID WHERE id = @SelectedIdFromAboveSelect;

我必须确保每一行只被选择一次。如果多个用户需要一个优惠券代码,SELECTUPDATE 之间有一个小的时间间隔。如果随后执行第二个SELECT,它可能会再次SELECT 同一行。我该如何防止呢?

【问题讨论】:

  • TOP 1 ... FROM tableName 所以你根据执行计划选择用户。

标签: sql sql-server database tsql sql-server-2014


【解决方案1】:

我猜你可以按相反的顺序做;我的意思是,你 UPDATE 带有用户 ID 的表,然后 SELECT 凭证代码。这样你应该没有任何问题。

【讨论】:

  • 对我来说,这个答案符合横向思维——喜欢它!在控件中工作以找出选择了哪个凭证代码(可能基于 max(id))并进行一些仔细检查以防没有可分配的凭证,你很好。
  • 这是如何工作的?如果用户不止一次出现在表中,您如何知道刚刚分配了哪个凭证代码?
  • 我同时解决了一些问题。就是这样,第一次更新,但使用子查询:UPDATE tableName SET UserId = @@UserId WHERE id = (SELECT TOP (1) id FROM tableName WHERE UserId IS NULL ORDER BY id ASC)。之后我可以做一个 SELECT * FROM tableName WHERE UserId = @@UserId
  • @Frisbee 一个用户在表中可能不超过一次。在另一张优惠券到期之前,我会检查他是否还没有在桌子上。
  • @Ollie 然后你又回到了如果在 select 和 update 之间添加了 userID 会怎样
【解决方案2】:

您可以通过使用output 子句返回update 语句中的值来做到这一点:

declare @ids table (userid int);

with toupdate as (
      SELECT TOP 1 *
      FROM tableName
      WHERE UserId IS NULL
     )
UPDATE toupdate
    SET UserId = @UserId
    OUTPUT inserted.UserId INTO @ids;

【讨论】:

  • 谢谢,这似乎是一种优雅的方式。
【解决方案3】:

你可以试试这个:

UPDATE t
SET userid = 99
OUTPUT inserted.id, inserted.vouchercode
FROM tablename t
WHERE userid IS NULL
AND id = (SELECT MIN(id) 
          FROM tablename 
          WHERE userid IS NULL)

OUTPUT 仅用于获取您实际选择的 id 和代码。

【讨论】:

    【解决方案4】:

    我认为这可能会有所帮助:

    SELECT DISTINCT * FROM tableName WHERE UserId IS NULL

    【讨论】:

      猜你喜欢
      • 2017-04-13
      • 2015-12-13
      • 2013-03-05
      • 1970-01-01
      • 1970-01-01
      • 2010-10-01
      • 1970-01-01
      • 2013-08-12
      • 2022-01-01
      相关资源
      最近更新 更多