Вопрос

В Oracle существует механизм генерации порядковых номеров, например;

CREATE SEQUENCE supplier_seq

    MINVALUE 1
    MAXVALUE 999999999999999999999999999
    START WITH 1
    INCREMENT BY 1
    CACHE 20;

А затем выполните инструкцию

supplier_seq.nextval

чтобы получить следующий порядковый номер.

Как бы вы создали такую же функциональность в MS SQL Server?

Редактировать:Я не ищу способы автоматической генерации ключей для записей таблицы.Мне нужно сгенерировать уникальное значение, которое я могу использовать в качестве (логического) идентификатора для процесса.Поэтому мне нужна точная функциональность, которую предоставляет Oracle.

Это было полезно?

Решение

Точного совпадения нет.

Эквивалентом является ИДЕНТИФИКАТОР, который вы можете задать в качестве типа данных при создании таблицы.SQLSERVER автоматически создаст текущий порядковый номер во время вставки.Последнее вставленное значение можно получить, вызвав SCOPE_IDENTITY() или обратившись к системной переменной @@IDENTITY (как указал Франс).

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

Редактировать:
SQL Server реализовал Последовательность, аналогичную Oracle.Пожалуйста, обратитесь к этому вопросу для получения более подробной информации.

Как бы вы реализовали последовательности в Microsoft SQL Server?

Другие советы

Identity - лучшее и наиболее масштабируемое решение, НО, если вам нужна последовательность, которая не является увеличивающимся значением int, например 00A, 00B, 00C или какой-либо специальной последовательностью, есть второй лучший метод.При правильной реализации он хорошо масштабируется, но при плохой реализации - плохо масштабируется.Я не решаюсь рекомендовать это, но то, что вы делаете, это:

  1. Вы должны сохранить "следующее значение" в таблице.Таблица может быть простой таблицей с одной строкой и одним столбцом и содержать только это значение.Если у вас есть несколько последовательностей, они могут совместно использовать таблицу, но вы могли бы получить меньше разногласий, имея отдельные таблицы для каждой.
  2. Вам нужно написать одну инструкцию update, которая увеличит это значение на 1 интервал.Вы можете поместить обновление в сохраненный процесс, чтобы упростить его использование и предотвратить повторение его в коде в разных местах.
  3. Правильное использование последовательности, чтобы она была разумно масштабируемой (нет, не так хорошо, как Identitiy :-), требует двух вещей:a.оператор update имеет специальный синтаксис, созданный именно для этой задачи, который будет как увеличивать, так и возвращать значение в одном операторе;b.вы должны извлечь значение из пользовательской последовательности ПЕРЕД началом транзакции и за пределами области действия транзакции.Это одна из причин масштабирования идентификатора - он возвращает новое значение независимо от объема транзакции для любого попытка вставляется, но не откатывается при сбое.Это означает, что он не будет блокироваться, а также означает, что у вас будут пробелы для неудачных транзакций.

Специальный синтаксис update немного варьируется в зависимости от версии, но суть в том, что вы выполняете присвоение переменной и обновление в одном и том же операторе.На 2008 год у Ицика Бен-Гана есть это изящное решение: http://www.sqlmag.com/Articles/ArticleID/101339/101339.html ?Объявление=1

Метод старой школы 2000 года и более поздних версий выглядит следующим образом:

ОБНОВИТЬ НАБОР таблиц последовательности @localVar = value = значение + 5 -- измените конечную часть в соответствии с вашей логикой увеличения

Это одновременно увеличит и вернет вам следующее значение.

Если у вас абсолютно не может быть пробелов (сопротивляйтесь этому требованию :-), то технически возможно поместить это обновление или процедуру в сторону остальной части вашего trnsaction, но вы СИЛЬНО страдаете от параллелизма, поскольку каждая вставка ожидает фиксации предыдущей.

Я не могу приписать это себе;Я научился всему этому у Ицика.

сделайте это поле полем идентификации.Поле получит свое значение автоматически.Вы можете получить последнее вставленное значение, вызвав SCOPE_IDENTITY() или обратившись к системной переменной @@IDENTITY

Предпочтительна функция SCOPE_IDENTITY().

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

Последовательности Oracle обладают высокой масштабируемостью.

Хорошо, я беру свои слова немного назад.Если вы действительно готовы сосредоточиться на параллелизме и разбирать числа по порядку, насколько это возможно при использовании последовательности, у вас есть шанс.Но поскольку вы, похоже, изначально не знакомы с t-sql, я бы начал искать некоторые другие варианты, когда (перенос приложения Oracle на MSSS - это то, что вы делаете)

Например, просто сгенерируйте GUID в функции "nextval".Это было бы масштабно.

Да, и НЕ используйте таблицу для всех значений, просто чтобы сохранить ваше максимальное значение в кэше.Вам пришлось бы заблокировать его, чтобы убедиться, что вы задаете уникальные значения, и именно здесь вы прекратите масштабирование.Вам нужно будет выяснить, есть ли способ кэширования значений в памяти и программного доступа к каким-то облегченным блокировкам - блокировкам памяти, а не блокировкам таблиц.

Я хотел бы, чтобы у SQL Server была эта функция.Это сделало бы так много вещей проще.

Вот как я справился с этой проблемой.

Создайте таблицу под названием tblIdentities.В этой таблице укажите строку с вашими минимальными и максимальными значениями и с указанием того, как часто следует сбрасывать Порядковый номер.Также введите имя новой таблицы (назовите ее tblMySeqNum).Выполнение этого позволяет довольно легко добавлять дополнительные генераторы порядковых номеров позже.

tblMySeqNum состоит из двух столбцов.ID (который является идентификатором int) и insertDate (который представляет собой столбец даты и времени со значением по умолчанию GetDate()).

Когда вам понадобится новое число seq, вызовите sproc, который вставляет в эту таблицу, и используйте SCOPE_IDENTITY(), чтобы создать идентификатор.Убедитесь, что вы не превысили максимальное значение в tblIdentities.Если у вас есть, то верните сообщение об ошибке.Если нет, верните свой Порядковый номер.

Теперь перейдем к сбросу настроек и очистке.У вас есть задание, которое выполняется так регулярно, как это необходимо, и которое проверяет все таблицы, перечисленные в tblIdentites (пока только одну), чтобы увидеть, нужно ли их сбрасывать.Если они достигли значения сброса или времени, то вызовите DBCC IDENT RESEED для имени таблицы, указанной в строке (tblMySeqNum в этом примере).Это также подходящее время, чтобы очистить нашу таблицу от лишних строк, которые вам на самом деле не нужны в этой таблице.

НЕ выполняйте очистку или повторное заполнение в вашем sproc, который получает идентификатор.Если вы это сделаете, то ваш генератор порядковых номеров вообще не будет хорошо масштабироваться.

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

Ваккано

Если у вас есть возможность обновиться до SQL Server 2012, вы можете использовать объекты SEQUENCE.Даже SQL Server 2012 Express поддерживает последовательности.

CREATE SEQUENCE supplier_seq
    AS DECIMAL(38)
    MINVALUE 1
    MAXVALUE 999999999999999999999999999
    START WITH 1
    INCREMENT BY 1
    CACHE 20;

SELECT NEXT VALUE FOR supplier_seq
SELECT NEXT VALUE FOR supplier_seq
SELECT NEXT VALUE FOR supplier_seq
SELECT NEXT VALUE FOR supplier_seq
SELECT NEXT VALUE FOR supplier_seq

Приводит к:

---------------------------------------
1

(1 row(s) affected)


---------------------------------------
2

(1 row(s) affected)


---------------------------------------
3

(1 row(s) affected)


---------------------------------------
4

(1 row(s) affected)


---------------------------------------
5

(1 row(s) affected)

Просто позаботьтесь о том, чтобы указать правильный тип данных.Если бы я не указал это, указанное вами МАКСИМАЛЬНОЕ ЗНАЧЕНИЕ не было бы принято, вот почему я использовал ДЕСЯТИЧНОЕ число с максимально возможной точностью.

Подробнее о ПОСЛЕДОВАТЕЛЬНОСТЯХ здесь: http://msdn.microsoft.com/en-us/library/ff878091.aspx

Возможно, на этот вопрос уже давным-давно был дан ответ...но начиная с SQL 2005, вы можете использовать ROW_NUMBER функция...примером может быть:

select ROW_NUMBER() OVER (ORDER BY productID) as DynamicRowNumber, xxxxxx,xxxxx

Тот самый OVER оператор использует ORDER BY для уникального первичного ключа в моем случае...

Надеюсь, это поможет...больше никаких временных таблиц или странных соединений!!

На самом деле это не ответ, но похоже, что последовательности поступят на SQLServer в 2012 году.

http://www.sql-server-performance.com/2011/sequence-sql-server-2011/

Не точный ответ, а дополнение к некоторым существующим ответам

SCOPE_IDENTITY (Transact-SQL)

SCOPE_IDENTITY, IDENT_CURRENT и @@IDENTITY являются аналогичными функциями потому что они возвращают значения, которые вставляются в столбцы идентификаторов.

IDENT_CURRENT не ограничен областью действия и сеансом;оно ограничено указанной таблицей.IDENT_CURRENT возвращает значение, сгенерированное для определенной таблицы в любом сеансе и любой области.Для получения дополнительной информации см. IDENT_CURRENT (Transact-SQL).

Это означает, что два разных сеанса могут иметь одинаковое идентификационное значение или порядковый номер, поэтому, чтобы избежать этого и получить уникальный номер для всех сеансов, используйте IDENT_CURRENT

Именно из-за этого IDENT_CURRENT не ограничен областью действия и сеансом;он ограничен указанной таблицей.нам нужно использовать SCOPE_IDENTITY(), потому что scope identity выдаст нам уникальный номер, сгенерированный в нашем сеансе, а уникальность обеспечивается самим identity.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top