Последовательность Oracle, но затем в MS SQL Server - PullRequest
14 голосов
/ 19 марта 2009

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

CREATE SEQUENCE supplier_seq

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

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

supplier_seq.nextval

для получения следующего порядкового номера.

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

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

Ответы [ 10 ]

15 голосов
/ 19 марта 2009

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

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

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

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

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

6 голосов
/ 29 июля 2009

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

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

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

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

ОБНОВЛЕНИЕ SequenceTable SET @localVar = значение = значение + 5 - измените хвостовую часть на вашу логику приращения

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

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

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

5 голосов
/ 19 марта 2009

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

Функция SCOPE_IDENTITY () является предпочтительной.

3 голосов
/ 19 марта 2009

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

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

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

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

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

1 голос
/ 25 марта 2013

Если вы можете выполнить обновление до 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)

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

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

1 голос
/ 17 мая 2009

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

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

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

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

1 голос
/ 20 марта 2009

Хотелось бы, чтобы в SQL Server была эта функция. Это облегчит многие вещи.

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

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

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

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

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

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

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

Vaccano

0 голосов
/ 29 ноября 2012

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

0 голосов
/ 26 апреля 2012

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

SCOPE_IDENTITY (Transact-SQL)

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

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

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

0 голосов
/ 10 февраля 2012

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

http://www.sql -server-performance.com / 2011 / последовательность-SQL-сервер-2011 /

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...