2009-10-09 3 views
7

Возможно ли в SQL (SQL Server) получить следующий идентификатор (целое число) из столбца идентификации в таблице до и без фактической вставки строки? Это не обязательно самый высокий ID плюс 1, если последняя строка была удалена.Получение следующего идентификатора без вставки строки

Я спрашиваю об этом, потому что нам приходится обновлять живой БД новыми строками. Идентификатор строки используется в нашем коде (например, Switch (ID) {Case ID:} и должен быть тем же. Если наша база данных разработки и live DB не синхронизирована, было бы неплохо заранее предсказать идентификатор строки Перед развертыванием.

Я мог бы, конечно SET IDENTITY OFF SET INSERT_IDENTITY ON или запустить транзакцию (это делает откат ID?) и т.д., но задавался вопросом, есть ли функция, которая вернула следующий идентификатор (без увеличения его) .

+0

Сделка не будет откатывать идентификационный счетчик, и всегда существует риск того, что какой-либо другой поток использует число, которое, по вашему мнению, вы получите позже. – idstam

+0

Спасибо за это @idstam Я подозревал это. – iWeasel

ответ

8

Edit:

Проведя несколько часов, сравнивающих целые отвалы страницы, я понял, что это легкий путь, и я должен, остался на DMVs.

Значение сохраняет резервную копию/восстановление, что является четким указанием на то, что оно хранится - я сбросил все страницы в БД и не смог найти местоположение/изменение, когда была добавлена ​​запись. Сравнение 200k строк дампов страниц не весело.

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

Итак, пройдя круг в кругу, я понял, что у DMV есть ответ.

create table foo (MyID int identity not null, MyField char(10)) 
insert into foo values ('test') 
go 10 

-- Inserted 10 rows 
select Convert(varchar(8),increment_value) as IncrementValue, 
    Convert(varchar(8),last_value) as LastValue 
from sys.identity_columns where name ='myid' 


-- insert another row 
insert into foo values ('test') 

-- check the values again 
select Convert(varchar(8),increment_value) as IncrementValue, 
    Convert(varchar(8),last_value) as LastValue 
from sys.identity_columns where name ='myid' 

-- delete the rows 
delete from foo 


-- check the DMV again 
select Convert(varchar(8),increment_value) as IncrementValue, 
    Convert(varchar(8),last_value) as LastValue 
from sys.identity_columns where name ='myid' 

-- value is currently 11 and increment is 1, so the next insert gets 12 
insert into foo values ('test') 
select * from foo 

Result: 
MyID  MyField 
----------- ---------- 
12   test  

(1 row(s) affected) 

Просто потому, что строки были удалены, последнее значение было не сбрасывается, поэтому последнее значение + приращение должно быть правильный ответ.

Также собираюсь написать эпизод в своем блоге.

Ох, и короткая стрижка, чтобы все это:

select ident_current('foo') + ident_incr('foo') 

Так что на самом деле оказываются просто - но все это предполагает никто не использовал свой идентификатор в то время как вы получили его обратно. Хорошо для расследования, но я бы не хотел использовать его в коде.

+0

Yikes! +1 за ответ, который заставил меня улыбнуться – iWeasel

+0

Я провел большую часть ночи, исследуя его, думая, что это сделает приличный блог, и разобрался. Редактирование моего ответа. – Andrew

+0

@ Andrew. Мысль о том, что у вас слишком много времени на ваших руках, возникла у меня. С другой стороны, большое спасибо. Отличный ответ. – iWeasel

2

Вместо того чтобы использовать столбец IDENTITY, можно использовать столбец UniqueIdentifier (GUID) в качестве уникальной строки идентификторов и вставить известные значения.

другой вариант (который я использую) является S ET IDENTITY_INSERT ON, где идентификаторы строк управляются одним управляемым источником одним документом.

+1

Отличная точка, но Гиды на самом деле не практичны на этом конкретном столе и немного голодны. В настоящее время я использую IDENTITY_INSERT. Это работает, но интересно, есть ли альтернатива. :) – iWeasel

+0

+1 для гидов. У гидов есть ограничение производительности относительно столбца автоинкремент (хотя дополнительное пространство, которое им требуется в строке, тривиально), но они полностью устраняют необходимость прыгать через обручи, подобные этому. – MusiGenesis

+0

Штраф в том случае, если вы используете GUID как кластерный ключ, тогда вы платите тяжелую цену как с точки зрения производительности, так и пространства. – Andrew

2

Вы можете довольно легко определить, что последнее значение, использованное является:

SELECT 
    last_value 
FROM 
    sys.identity_columns 
WHERE 
    object_id = OBJECT_ID('yourtablename') 

Обычно, следующий идентификатор будет last_value + 1 - но нет никакой гарантии, что.

Marc

+1

Точно; нет никакой гарантии, поэтому я подумал, есть ли альтернатива. :) – iWeasel

+0

Нет, другого пути нет - SQL Server будет когда-либо действительно выдавать идентификатор, когда вы на самом деле выполняете INSERT - нет способа подделать это :-( –

2

Это немного странно, но он будет работать:

Если вы хотите знать следующее значение, начать получать наибольшее значение плюс один:

SELECT max(id) FROM yourtable 

Для выполните эту работу, вам необходимо сбросить идентификатор на вставке:

DECLARE @value INTEGER 

SELECT @value = max(id) + 1 FROM yourtable 

DBCC CHECKIDENT (yourtable, reseed, @value) 

INSERT INTO yourtable ... 

Неправильно точно изящное решение, но у меня еще не было моего кофе ;-)

(Это также предполагает, что ничего не делается с таблицей с помощью вашего процесса или любого другого процесса между первым и вторым блоками кода).

+0

Это может быть не изящно, но я отмечу это как ответ для таблицы, в которых вы можете быть уверены, что перед запуском этой новой строки не будет вставлена ​​новая строка. – iWeasel

+0

Извините, Джефф, @ Андрей потратил всю ночь на отличное редактирование. Работает с удовольствием. Нужно переписать ответ. – iWeasel

7

попробовать IDENT_CURRENT:

Select IDENT_CURRENT('yourtablename') 

Это работает, даже если вы не вставили ни одной строки в текущей сессии:

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

+1

Ницца.Это получает самое последнее значение, и страница MSDN предупреждает о том, что «будьте осторожны при использовании IDENT_CURRENT для прогнозирования следующего сгенерированного значения идентификации. Фактическое сгенерированное значение может отличаться от IDENT_CURRENT плюс IDENTITY_SEED из-за вставок, выполняемых другими сеансами». – PaulG

Смежные вопросы