2014-01-15 2 views
0

Я создал таблицу с именем tblEmployees с кодом -Столбец Identity SQL Server не ведет себя правильно?

Create table tblEmployees 
(
    EmployeeID int identity primary key, 
    Name nvarchar(30), 
    Salary float, 
    Gender tinyint 
) 

Затем я вставил с ценностно

insert into tblEmployees values ('Akmal', 5000, 0) 
insert into tblEmployees values ('Shakira', 6000, 1) 
insert into tblEmployees values ('Kiron', 7000, 2) 
insert into tblEmployees values ('Jamil', 5500, 0) 
insert into tblEmployees values ('Faul', 4800, 4) 

Но, когда значения показаны -

EmployeeID Name  Salary Gender 
2   Akmal  5000   0 
3   Shakira 6000   1 
4   Kiron  7000   2 
5   Jamil  5500   0 
7   Faul  4800   4 

Мой вопрос, почему Столбец EmployeeID начинался с 2? А где 6? Не следует ли это автоматически увеличивать?

+2

«ИДЕНТИФИКАЦИЯ (1,1)» запустила бы столбец идентификации с шагом 1 с шагом 1. – user2989408

+0

Проблема заключается в том, что имеет значение, если EmployeeID имеет пробелы. – Zane

ответ

2

Ваш сценарий T-SQL неполный, так как генерируются значения IDENTITY, начиная с 1 (и заканчивая 5).

Примечание № 0: Я только пытаюсь описать некоторые причины для тех, которые не имеют значений IDENTITY.

Примечание № 1: не запускайте этот скрипт на рабочем сервере.

Примечание № 2: Использование IDENTITY в определении столбца IDENTITY(1,1) < =>IDENTITY(seed value/initial value=1,increment value=1).

Примечание № 3: Вам следует избегать использования DBCC CHECKIDENT, если вы не знаете о consequences of this command.

Первое отсутствующее значение (возможное объяснение):

почему EmployeeID колонна начала с 2?

Выполните следующий скрипт:

IF OBJECT_ID(N'dbo.tblEmployees') IS NOT NULL 
    DROP TABLE dbo.tblEmployees; 
GO 
Create table tblEmployees 
(
    EmployeeID int identity primary key, 
    Name nvarchar(30), 
    Salary float, 
    Gender tinyint 
) 
GO 
insert into tblEmployees values ('Akmal', 5000, 0) 
insert into tblEmployees values ('Shakira', 6000, 1) 
insert into tblEmployees values ('Kiron', 7000, 2) 
insert into tblEmployees values ('Jamil', 5500, 0) 
insert into tblEmployees values ('Faul', 4800, 4) 
GO 
SELECT SCOPE_IDENTITY() AS [Last IDENTITY #1]; 
/* 
Last IDENTITY #1 
---------------- 
5 
*/ 
GO 

На данный момент последнее значение IDENTITY генерируется для этой таблицы (как вы можете видеть) 5, а не 7 (как ваш пример).

SELECT * FROM dbo.tblEmployees; 
/* 
EmployeeID Name       Salary     G 
----------- ------------------------------ ---------------------- - 
1   Akmal       5000     0 
2   Shakira      6000     1 
3   Kiron       7000     2 
4   Jamil       5500     0 
5   Faul       4800     4 
*/ 
GO 

Все строки имеют непрерывные значения IDENTITY: нет пробелов.

В настоящее время, по некоторым причинам, кто-то удаляет все строки из dbo.tblEmployees, а также решает сброса (Reseed) последнее значение идентичности (которое равно 5) до 1 (от 5 до 1).

DELETE dbo.tblEmployees; 
GO 
DBCC CHECKIDENT('dbo.tblEmployees', RESEED, 1); 
GO 
SELECT SCOPE_IDENTITY() AS [Last IDENTITY #2]; 
/* 
Last IDENTITY #2 
---------------- 
1 
*/ 
GO 

Теперь последнее значение IDENTITY равно 1 (из-за этого RESEED 1).

insert into tblEmployees values ('Akmal', 5000, 0) 
insert into tblEmployees values ('Shakira', 6000, 1) 
insert into tblEmployees values ('Kiron', 7000, 2) 
insert into tblEmployees values ('Jamil', 5500, 0) 
insert into tblEmployees values ('Faul', 4800, 4) 
GO 
SELECT * FROM dbo.tblEmployees; 
GO 
/* 
EmployeeID Name       Salary     Gender 
----------- ------------------------------ ---------------------- ------ 
2   Akmal       5000     0 
3   Shakira      6000     1 
4   Kiron       7000     2 
5   Jamil       5500     0 
6   Faul       4800     4 
*/ 

Когда я вставляю эти строки снова, первое сгенерированное значение IDENTITY равно 2 (на этот раз).

Почему? Причина описана в MSDN:

«Если ни одна строка не была вставлена ​​в таблицу, так как таблица была создана, или , если все строки были удалены с помощью оператора TABLE TRUNCATE, первая строка вставляется после вас запустить DBCC CHECKIDENT использует new_reseed_value как тождество в противном случае, следующая строка вставляется использует new_reseed_value + текущее значение приращения "

последняя формула объясняет, почему этот раз первое значение IDENTITY равно 2:..

new_reseed_value (1 - из-за RESEED 1) + значение приращения тока (1 - см. Примечание № 2) = 1 + 1 = 2.

Примечание # 4: При использовании TRUNCATE TABLE вместо DELETE то первая строка вставляется после TRUNCATE TABLE будет иметь значение ID = семян (примечание 2 #) или new_reseed_value = 1. Таким образом, в этом случае вы не требуется DBCC(..., RESEED, 1).

Второе отсутствующее значение (возможное объяснение):

А где 6?

DELETE dbo.tblEmployees WHERE EmployeeID = 6 
insert into tblEmployees values ('Faul', 4800, 4) 
GO 
SELECT SCOPE_IDENTITY() AS [Last IDENTITY #3]; 
/* 
Last IDENTITY #3 
---------------- 
7 
*/ 
GO 
SELECT * FROM dbo.tblEmployees; 
GO 
/* 
EmployeeID Name       Salary     Gender 
----------- ------------------------------ ---------------------- ------ 
2   Akmal       5000     0 
3   Shakira      6000     1 
4   Kiron       7000     2 
5   Jamil       5500     0 
7   Faul       4800     4 
*/ 
15

Не полагайтесь на столбцы IDENTITY, чтобы создать непрерывный набор значений без пробелов. Период. Это не гарантируется вообще; несколько вещей могут вызвать пробелы, такие как откат, удаление, повтор и т. д. Я не верю, что вы воспроизвели эту проблему с этим точным кодом выше; вероятно, была иная деятельность между этими утверждениями INSERT.

Для таких суррогатных и бессмысленных ценностей вам действительно все равно, есть ли пробелы или нет. Если вам небезразличны пробелы, используйте другой метод (например, сериализуемое решение max() + 1) - просто имейте в виду, что вы занимаетесь разрывами в задачах масштабируемости/параллелизма. Другой ответ (который вы приняли, но я подозреваю, удаляются) сказал:

Если вы хотите иметь столбец идентификаторов с надежными и заданными значениями, то вам необходимо установить IDENTITY_INSERT в положение ON на этой колонке, вставьте значения (с определенными значениями ID), а затем установите для параметра IDENTITY_INSERT значение OFF.

Это работает, только если вы уже знаете значения, которые хотите вставить в этот столбец. Что в первую очередь поражает цель собственности IDENTITY. Если вы еще не знаете, какие значения нужно вставить (например, что означает «следующий» ID), это означает, что вам нужно найти SELECT MAX() из таблицы и добавить 1 к нему. Это означает, что все это должно быть сериализуемо, иначе кто-то может прочитать то же самое значение MAX() и добавить к нему те же +1. Таким образом, помимо того, что свойство IDENTITY бесполезно, если вы все равно отказываетесь от генерируемого значения, оно также убивает масштабируемость, эффективно ограничивая параллелизм до 1. Я настоятельно рекомендую вам сильно взвесить этот подход перед его внедрением.

Вместо этого я предлагаю вам использовать колонку IDENTITY и не зависеть от разрывов. Они произойдут, вы не можете с этим поделать, и в любом случае это не должно волновать. Кого волнует, если нет сотрудника № 6?

+0

Не могли бы вы объяснить, почему? – user2989408

+0

Теперь это не так интересно, потому что у меня была база данных, пропускающая 1000 идентификаторов на моем общем размещенном сервере SQL Server. По крайней мере, я знаю, что кто-то еще видел с ним странности. –

+3

@ Майкл, что он немного другой; см. [эта ошибка в Connect] (http://connect.microsoft.com/SQLServer/feedback/details/739013/failover-or-restart-results-in-reseed-of-identity). Это связано с тем, как механизм кэширования для значений идентичности изменился с введением SEQUENCE в SQL Server 2012. –

-4

Не знаю, почему мой предыдущий ответ был отклонен и удален или заблокирован, но если вы хотите иметь столбец идентификаторов с надежными и заданными значениями, то вам необходимо установить IDENTITY_INSERT в положение ON на этой колонке, вставка ваши значения (с определенными значениями ID), а затем установите IDENTITY_INSERT обратно в положение OFF.

Если вам все равно, каковы ценности (что, вероятно, имеет место в таблице Employees), то забудьте об этом и научитесь жить с тем, чем бы эти ценности не оказались.

+1

Пожалуйста, см. Мой ответ за то, почему это предложение возиться с 'IDENTITY_INSERT' совершенно не имеет смысла. –

+0

Реальная ситуация: мне пришлось импортировать данные для таблицы поиска из предыдущей реализации. Для обратной совместимости я должен был уважать идентификаторы из предыдущей реализации, и после этого все новые значения поиска получат автоматически генерируемые значения. В этом случае решение заключалось в написании сценариев пост-развертывания с IDENTITY_INSERT, установленным на OFF, а затем ON. Извините, в отличие от вас я не говорю о теории, я говорю о реальной жизненной ситуации. – NicVerAZ

+0

Вы писали: «Кроме того, для этого вам нужно знать, какое значение нужно вставить. Это означает, что вам нужно выбрать SELECT MAX() из таблицы. Что все это нужно для сериализации, иначе кто-то может прочитать то же MAX() и добавьте к нему тот же +1 «Чувак, прочитайте, что я написал: ВСТАВЬТЕ ВАШИ ЦЕННОСТИ С СПЕЦИФИЧЕСКИМИ ЦЕННЫМИ ЦЕННОСТЯМИ. Вы читаете требования перед кодированием? – NicVerAZ

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