2

在我的数据库中添加项目时,我需要它来自动确定字段 DisplayOrder 的值。Identity(自动增量)将是一个理想的解决方案,但我需要能够以编程方式更改(更新)DisplayOrder 列的值,而 Identity 似乎不允许这样做。目前,我使用以下代码:

CREATE PROCEDURE [dbo].[AddItem]

AS

DECLARE @DisplayOrder INT

SET @DisplayOrder = (SELECT MAX(DisplayOrder) FROM [dbo].[MyTable]) + 1

INSERT INTO [dbo].[MyTable] ( DisplayOrder ) VALUES ( @DisplayOrder )

这是做到这一点的好方法还是有更好/更简单的方法?

4

5 回答 5

1

您可以将递增列设置为使用标识属性。然后,在需要将值插入列的过程中,您可以SET IDENITY_INSERT在批处理中使用该命令。

对于要使用标识属性的插入,请从插入语句的列列表中排除标识列:

INSERT INTO [dbo].[MyTable] ( MyData ) VALUES ( @MyData )

如果要在为标识列提供值的位置插入行,请使用以下命令:

SET IDENTITY_INSERT MyTable ON

INSERT INTO [dbo].[MyTable] ( DisplayOrder, MyData )
VALUES ( @DisplayOrder, @MyData )

SET IDENTITY_INSERT MyTable OFF

您应该能够在没有任何其他步骤的情况下更新该列。

您可能还想查看该DBCC CHECKIDENT命令。此命令将设置您的下一个身份值。如果要插入下一个标识值可能不合适的行,则可以使用该命令设置新值。

DECLARE @DisplayOrder INT

SET @DisplayOrder = (SELECT MAX(DisplayOrder) FROM [dbo].[MyTable]) + 1

DBCC CHECKIDENT (MyTable, RESEED, @DisplayOrder)
于 2010-08-10T21:37:51.000 回答
1

“Microsoft SQL Server 2008 内部:T-SQL 查询”中对此问题的解决方案

CREATE TABLE dbo.Sequence(
 val int IDENTITY (10000, 1) /*Seed this at whatever your current max value is*/
 )

GO

CREATE PROC dbo.GetSequence
@val AS int OUTPUT
AS
BEGIN TRAN
    SAVE TRAN S1
    INSERT INTO dbo.Sequence DEFAULT VALUES
    SET @val=SCOPE_IDENTITY()
    ROLLBACK TRAN S1 /*Rolls back just as far as the save point to prevent the 
                       sequence table filling up. The id allocated won't be reused*/
COMMIT TRAN

或者同一本书中的另一种更容易分配范围的替代方法。(您需要考虑是从事务内部还是外部调用它——内部会阻塞其他并发事务,直到第一个事务提交)

CREATE TABLE dbo.Sequence2(
 val int 
 )

GO

INSERT INTO dbo.Sequence2 VALUES(10000);

GO

CREATE PROC dbo.GetSequence2
@val AS int OUTPUT,
@n as int =1
AS
UPDATE dbo.Sequence2 
SET @val = val = val + @n;

SET @val = @val - @n + 1; 
于 2010-08-11T21:23:09.733 回答
0

这是我保留的解决方案:

CREATE PROCEDURE [dbo].[AddItem]

AS

DECLARE @DisplayOrder INT

BEGIN TRANSACTION

SET @DisplayOrder = (SELECT ISNULL(MAX(DisplayOrder), 0) FROM [dbo].[MyTable]) + 1

INSERT INTO [dbo].[MyTable] ( DisplayOrder ) VALUES ( @DisplayOrder )

COMMIT TRANSACTION
于 2010-08-11T21:01:29.650 回答
-1

您应该做的一件事是添加命令,以便您的过程作为事务运行,否则同时运行的两个插入可能会在 DisplayOrder 中产生具有相同值的两行。

这很容易实现:添加

begin transaction

在您的程序开始时,以及

commit transaction

在末尾。

于 2010-08-10T21:08:06.647 回答
-1

您的方式工作正常(稍作修改)并且很简单。我会将它包装在@David Knell 所说的交易中。这将导致如下代码:

CREATE PROCEDURE [dbo].[AddItem]

AS

DECLARE @DisplayOrder INT

BEGIN TRANSACTION

SET @DisplayOrder = (SELECT MAX(DisplayOrder) FROM [dbo].[MyTable]) + 1

INSERT INTO [dbo].[MyTable] ( DisplayOrder ) VALUES ( @DisplayOrder )

COMMIT TRANSACTION

将您的 SELECT 和 INSERT 包装在事务中可确保您的DisplayOrder值不会被AddItem复制。如果您同时进行大量添加(每秒很多),MyTable上可能会出现争用,但对于偶尔的插入,这不会有问题。

于 2010-08-10T21:53:20.900 回答