【问题标题】:SQL Server: insert next available intSQL Server:插入下一个可用的 int
【发布时间】:2011-06-18 17:02:29
【问题描述】:

我正在处理 SQL Server 中的一个表,该表具有一个 serial_no 列,该列被定义为非 null int。它似乎不是一个自动递增字段,就好像我将该列从插入语句中删除一样,我收到一条错误消息,指出 serial_no 字段不能为空。

那么如何插入下一个可用的数字?

我试过了:

INSERT INTO mytable (serial_no) VALUES ( (SELECT MAX(serial_no)+1 FROM mytable))

但我收到一条错误消息,提示不能在此上下文中使用子查询。

编辑:此表用于现成产品,因此我无法更改设计并使 serial_no 列自动递增。

【问题讨论】:

  • 它必须在所有行中都是唯一的吗?答案中推荐的方法通常不是并发安全的,例如您最终可能会出现重复......您要么需要 a) 将其设为 INT IDENTITY 列并让 SQL Server 担心它,b) 比 obviuos SELECT MAX(serial_no)+1 做更多的工作,或者 c) 等待对于 SQL Server 2011 并使用它的概念 SEQUENCES
  • marc_s,我完全同意,但不幸的是我无法更改数据库设计。如果我锁定表,插入然后解锁怎么办?这会保护它免受欺骗吗?还是等待中的查询只是等待锁释放然后插入重复的#?
  • 您能否运行跟踪以确定第 3 方应用程序如何创造价值并做同样的事情?我会说,如果没有标识列,他们可能会使用表来保存下一个值。已经有一个答案提到了这种技术。

标签: sql sql-server insert auto-increment


【解决方案1】:

您可以通过锁定提示提高写入并发性

INSERT INTO mytable (serial_no, value)
SELECT MAX (serial_no)+1, @value 
FROM mytable WITH (ROWLOCK, XLOCK, HOLDLOCK)

如果性能不重要,请尝试使用 TABLOCKX 代替 ROWLOCK、XLOCK

但是,鉴于这不安全,您需要重试

DECLARE @retry bit
SET @retry = 1

WHILE @Retry = 1
BEGIN
    BEGIN TRY
        INSERT INTO mytable (serial_no, value)
        SELECT MAX (serial_no)+1, @value 
        FROM mytable WITH (ROWLOCK, XLOCK, HOLDLOCK)

        SET @Retry = 0
    END TRY
    BEGIN CATCH
        IF ERROR_NUMBER() <> 2627  --PK violation
            RAISERROR ('blah', 16, 1)
    END CATCH
END

或者改成一个 IDENTITY 列并正确地做...

【讨论】:

  • 身份是最好的选择。但是,在某些情况下需要手动管理的唯一键。这恰好是我现在所处的情况。客户想要一个唯一的 FileNumber,它是连续的、用户可编辑的,并且每年都会更改序列的开头
  • @George:我们现在在 SQL Server 2012 中拥有此类东西的序列
【解决方案2】:

可以通过删除 VALUES 来修复错误

INSERT INTO mytable (serial_no, value)

SELECT MAX(serial_no)+1 ,
@value 
FROM mytable)

但这是个坏主意。 MAX(serial_no)+1 存在竞争条件(例如,两个插入的 Max(Serial_no) 值相同。

最好使用自动增量字段。您还可以创建一个表来存储当前的下一个值并将其递增而不是使用最大值。

【讨论】:

  • +1 用于提及使用此 MAX()+1 方法重复的可能性;并提出自增方案
  • 问题是它不是我的表或应用程序。我无法改变它。
【解决方案3】:
INSERT INTO mytable (serial_no) SELECT MAX(serial_no)+1 FROM mytable

【讨论】:

  • 不安全 - 如果两个 INSERT 几乎同时从两个连接发生,可能会导致重复......
【解决方案4】:

尝试不使用 VALUES:

INSERT INTO mytable (serial_no) SELECT MAX(serial_no)+1 FROM mytable

【讨论】:

  • 不安全 - 如果两个 INSERT 几乎同时从两个连接发生,可能会导致重复......
猜你喜欢
  • 1970-01-01
  • 2011-05-31
  • 1970-01-01
  • 2014-08-17
  • 1970-01-01
  • 2022-01-07
  • 1970-01-01
  • 2023-03-17
相关资源
最近更新 更多