2013-11-19 4 views
2

Я прочитал несколько сообщений о TSQL Identity Bug и играл с использованием SEQUENCE. Тем не менее, мне любопытно сбросить значение SEQUENCE по значению ID в таблице. Для примера:Сброс последовательности Последовательность

CREATE SEQUENCE Inc 
    AS INT 
    START WITH 1 
    INCREMENT BY 1 
    CYCLE 
    CACHE 

-- Quick ability to redo everything if needed: 
-- DROP SEQUENCE Inc 

-- Our table grabs the next sequence for our ID field: 
CREATE TABLE SequenceID(
    NewIDField INT DEFAULT NEXT VALUE FOR Inc, 
    Name VARCHAR(100) 
) 

INSERT INTO SequenceID (Name) 
VALUES ('John') 
    , ('Tiffany') 
    , ('Bob') 
    , ('Jessica') 

SELECT * 
FROM SequenceID 

-- We remove Bob: 
DELETE FROM SequenceID 
WHERE NewIDField = 3 

-- ID value 3 is gone; it moves from 1 to 2 to 4 
SELECT * 
FROM SequenceID 

INSERT INTO SequenceID (Name) 
VALUES ('David') 
    , ('Rosa') 
    , ('Samuel') 

-- ID 3 doesn't exist because the SEQUENCE grabs the next value from 4 
SELECT * 
FROM SequenceID 

-- Let's just reset our ID 
;WITH ResetIt AS(
    SELECT ROW_NUMBER() OVER (ORDER BY NewIDField) AS ID 
     , NewIDField AS ExistingID 
     , Name 
    FROM SequenceID 
) 
UPDATE SequenceID 
SET NewIDField = ResetIt.ID 
FROM ResetIt 
WHERE SequenceID.NewIDField = ResetIt.ExistingID 

-- Yay! 
SELECT * 
FROM SequenceID 

INSERT INTO SequenceID (Name) 
VALUES ('Sarah') 

-- Oh Sarah, tsk tsk. 
SELECT * 
FROM SequenceID 

DROP TABLE SequenceID 

Есть ли способ автоматически выполнять это с ПОСЛЕДОВАТЕЛЬНОСТЬЮ, где мы можем определить последнее значение и начинаем там (по аналогии с переустановкой), так как даже с IDENTITY, если удалить значение, мы по-прежнему должны RESEED, см:

CREATE TABLE IDID(
    ID INT IDENTITY(1,1), 
    I INT 
) 

INSERT INTO IDID (I) 
VALUES (1),(2),(3),(4) 

SELECT * 
FROM IDID 

DELETE FROM IDID 
WHERE ID = 3 

INSERT INTO IDID (I) 
VALUES (5),(6),(7) 

SELECT * 
FROM IDID 

DROP TABLE IDID 
+0

Похоже, вы пытаетесь достичь так называемого «бесщеточного» столбца идентификатора. Если это так, я бы посоветовал это сделать; это вызывает больше головных болей, чем любой выигрыш, который вы получите. –

+0

Мой совет: Не делай этого! Если эти цифры являются ключами, то повторное использование их - плохая идея. Например, используя ваш код, у Боба есть ключ из 3, но после удаления строки Боба и нумерации таблицы ключ 3 назначается Джессике. Что произойдет, если у Боба появится трудовой договор с «Employee ID 3»? Что, если это система заказов, и Боб появляется со счетом «Номер заказа 3»? Это будет иметь потенциально разрушительные юридические последствия и последствия для соблюдения, не говоря уже о проблемах с целостностью данных. –

+0

Если числа не являются ключами, и вам нужны только их на стадии отчетности, а затем добавляйте их только на стадии отчетности, используя такие функции, как RANK(), DENSE_RANK() и ROW_NUMBER(). –

ответ

8

После выполнения вашего обновления, вам придется запускать некоторые динамический SQL, поскольку ALTER SEQUENCE принимает только константу для запускался с пунктом:

DECLARE @resetSQL nvarchar(255) = 'ALTER SEQUENCE Inc RESTART WITH ' + (SELECT CAST(MAX(NewIDField)+1 as nvarchar(10)) FROM SequenceID); 

exec sp_executesql @resetSQL; 
Смежные вопросы