SQL Server - Автоинкремент, который позволяет операторы UPDATE - PullRequest
2 голосов
/ 11 августа 2010

При добавлении элемента в мою базу данных он мне нужен, чтобы автоматически определить значение для поля DisplayOrder.Идентификация (автоинкремент) была бы идеальным решением, но мне нужно иметь возможность программно изменять (UPDATE) значения столбца 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 )

Это хороший способ сделать это или есть лучший / более простой способ?

Ответы [ 5 ]

2 голосов
/ 12 августа 2010

Решение этой проблемы из «Внутри 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; 
2 голосов
/ 11 августа 2010

Вы можете установить свой увеличивающийся столбец, чтобы использовать свойство identity. Затем в процессах, которым нужно вставить значения в столбец, вы можете использовать команду SET IDENITY_INSERT в вашем пакете.

Для вставок, в которых вы хотите использовать свойство identity, столбец идентификаторов исключается из списка столбцов в инструкции вставки:

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)
0 голосов
/ 12 августа 2010

Вот решение, которое я сохранил:

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
0 голосов
/ 11 августа 2010

Ваш способ работает нормально (с небольшой модификацией) и прост. Я бы обернул его в транзакцию, как сказал @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 , но для случайных вставок это не будет проблемой.

0 голосов
/ 11 августа 2010

Одна вещь, которую вы должны сделать, это добавить команды, чтобы ваша процедура выполнялась как транзакция, в противном случае две операции вставки, выполняющиеся одновременно, могут создать две строки с одинаковым значением в DisplayOrder.

Этого достаточно легко достичь: добавить

begin transaction

в начале вашей процедуры и

commit transaction

в конце.

...