Сведения о вопросе

Henry

05:39, 25th August, 2020

Теги

Могу ли я поддерживать состояние между вызовами SQL Server UDF?

Просмотров: 458   Ответов: 3

У меня есть скрипт SQL, который вставляет данные (через операторы INSERT, которые в настоящее время числятся в тысячах), один из столбцов содержит уникальный идентификатор (хотя и не тип IDENTITY, а простой ol' int), который на самом деле уникален в нескольких разных таблицах.

Я хотел бы добавить функцию scalar в свой скрипт, который получает следующий доступный ID (т. е. последний раз использовался ID + 1), но я не уверен, что это возможно, потому что, похоже, нет способа использовать глобальную или статическую переменную из UDF, я не могу использовать временную таблицу, и я не могу обновить постоянную таблицу из функции.

В настоящее время мой скрипт выглядит так:

   declare @v_baseID int 
   exec dbo.getNextID @v_baseID out  --sproc to get the next available id
   --Lots of these - where n is a hardcoded value
   insert into tableOfStuff (someStuff, uniqueID) values ('stuff', @v_baseID + n ) 
   exec dbo.UpdateNextID @v_baseID + lastUsedn  --sproc to update the last used id

Но я бы хотел, чтобы это выглядело так:

   --Lots of these
   insert into tableOfStuff (someStuff, uniqueID) values ('stuff', getNextID() ) 

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

На данный момент мы используем SQL Server 2005.

правки для уточнения:

Два пользователя ударяя это не произойдет. Это сценарий обновления, который будет выполняться только один раз и никогда одновременно.

Фактический sproc не имеет префикса sp_, исправлен пример кода.

В обычном использовании мы используем таблицу идентификаторов и sproc, чтобы получить IDs по мере необходимости, я просто искал более чистый способ сделать это в этом скрипте, который по существу просто сбрасывает кучу данных в БД.



  Сведения об ответе

dumai

01:43, 16th August, 2020

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

Вы ничего не упускаете; сервер SQL не поддерживает глобальные переменные, и он не поддерживает изменение данных в пределах UDFs. И даже если вы хотите сделать что-то вроде kludgy, как с помощью CONTEXT_INFO (см. http://weblogs.sqlteam.com/mladenp/archive/2007/04/23/60185.aspx), вы не можете установить это из UDF в любом случае.

Есть ли способ обойти "hardcoding" смещения, сделав эту переменную и зациклив ее на итерации, делая вставки в этом цикле?


  Сведения об ответе

9090

13:10, 26th August, 2020

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

sp_getNextID

никогда не префикс procs с sp_, это имеет значение производительности, потому что оптимизатор сначала проверяет master DB, чтобы увидеть, существует ли этот proc там, а затем локальный DB, а также если MS решит создать sp_getNextID в пакете обновления, ваш никогда не будет выполнен


  Сведения об ответе

прога

07:00, 27th August, 2020

Вероятно, это будет больше работы, чем стоит, но вы можете использовать статические переменные C#/VB в SQL CLR UDF, поэтому я думаю, что вы сможете делать то, что хотите, просто увеличивая эту переменную каждый раз, когда вызывается UDF. Статическая переменная будет потеряна всякий раз, когда выгружается домен приложения, конечно. Поэтому, если вам нужна непрерывность вашего ID от одного дня до следующего, вам понадобится способ, при первом доступе к NextId, опросить все таблицы, которые используют этот ID, чтобы найти самое высокое значение.


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться