Правильные способы узнать id после INSERT в MS SQL 2012
От: Michael7 Россия  
Дата: 16.04.16 12:45
Оценка:
Вот что стоило разработчикам SQL позволить INSERT возвращать значения автоинкрементируемых полей после вставки? Лишнего геморойства было бы меньше. Пока что вижу три способа узнать значение автоикремента и не знаю какой самый правильный.

1) Так сейчас делаю. После вставки сразу SELECT Where по вставленным полям и получаю id записи. Минус: если найденных записей несколько — нет гарантии, что у вставленной записи максимальный номер. Параллельно могла произойти еще одна вставка и вообще у автоинкрементного поля кажется гарантируется только уникальность, но не возрастание. Впрочем, тут могу ошибаться. На практике однако часто это не существенно или не случается.

2) Использовать SCOPE_IDENTITY() Минус тот же. Нет гарантии, что никто не добавил запись.

3) Триггер на вставку в таблицу, который пишет id в отдельную таблицу. Можно запутаться

В принципе есть еще вариант. Отказаться от автоинкремента, но оставить ограничение на уникальность и самому присваивать id, если возникнет ошибка неуникальности, значит, кто-то параллельно добавил и надо просто продолжать добавлять записи с id++ пока не добавится.

Вот как корректнее всего даже и не знаю. А может я и вовсе чего-то не понял.
mssql insert
Re: Правильные способы узнать id после INSERT в MS SQL 2012
От: andrey82  
Дата: 16.04.16 12:55
Оценка: 6 (1) +1
Здравствуйте, Michael7, Вы писали:

M>Вот что стоило разработчикам SQL позволить INSERT возвращать значения автоинкрементируемых полей после вставки? Лишнего геморойства было бы меньше. Пока что вижу три способа узнать значение автоикремента и не знаю какой самый правильный.


M>Вот как корректнее всего даже и не знаю. А может я и вовсе чего-то не понял.


Нужно получать значения произвольных автоикрементируемых полей? Или только PK поле с назначенным IDENTITY() ?
INSERT INTO ... (...) 
OUTPUT INSERTED.IDENTITYCOL  
VALUES (...)
Не пойдет ?
Re[2]: Правильные способы узнать id после INSERT в MS SQL 20
От: Michael7 Россия  
Дата: 16.04.16 13:11
Оценка:
Здравствуйте, andrey82, Вы писали:


A>Нужно получать значения произвольных автоикрементируемых полей? Или только PK поле с назначенным IDENTITY() ?


Достаточно PK

A>
A>INSERT INTO ... (...) 
A>OUTPUT INSERTED.IDENTITYCOL  
A>VALUES (...)
A>
Не пойдет ?


Хм, спасибо про output.inserted просто не знал. Попробую.
Отредактировано 16.04.2016 13:11 Michael7 . Предыдущая версия .
Re: Правильные способы узнать id после INSERT в MS SQL 2012
От: vsb Казахстан  
Дата: 16.04.16 13:36
Оценка:
Например в JDBC есть метод, который возвращает все автосгенерированные поля. По идее любой вменяемый драйвер к БД должен позволять это делать.
Re: Правильные способы узнать id после INSERT в MS SQL 2012
От: Lexey Россия  
Дата: 16.04.16 18:56
Оценка: +3
Здравствуйте, Michael7, Вы писали:

M>2) Использовать SCOPE_IDENTITY() Минус тот же. Нет гарантии, что никто не добавил запись.


Хм... зачем тебе гарантия, что кто-то еще не добавил запись? Обычно нужен identity записи, добавленной твоим батчем. SCOPE_IDENTITY() его и вернет.
"Будь достоин победы" (c) 8th Wizard's rule.
Re[2]: Правильные способы узнать id после INSERT в MS SQL 2012
От: Michael7 Россия  
Дата: 16.04.16 21:42
Оценка:
Здравствуйте, Lexey, Вы писали:

L>Здравствуйте, Michael7, Вы писали:


M>>2) Использовать SCOPE_IDENTITY() Минус тот же. Нет гарантии, что никто не добавил запись.


L>Хм... зачем тебе гарантия, что кто-то еще не добавил запись? Обычно нужен identity записи, добавленной твоим батчем. SCOPE_IDENTITY() его и вернет.


Я думал оно вообще вернет последний identity в базе.
Re: Правильные способы узнать id после INSERT в MS SQL 2012
От: IB Австрия http://rsdn.ru
Дата: 17.04.16 17:16
Оценка: +3
Здравствуйте, Michael7, Вы писали:

M>Вот что стоило разработчикам SQL позволить INSERT возвращать значения автоинкрементируемых полей после вставки?

Вот что стоило документацию внимательно почитать?
https://technet.microsoft.com/en-us/library/aa259185(v=sql.80).aspx

В данном случае правильный способ — SCOPE_IDENTITY(). Параллельные транзакции не влияют, триггеры не влияют.
Мы уже победили, просто это еще не так заметно...
Re: Правильные способы узнать id после INSERT в MS SQL 2012
От: fplab Россия http://fplab.h10.ru http://fplab.blogspot.com/
Дата: 18.04.16 05:56
Оценка: -4
Что-то мне подсказывает, что тут есть засада, но что если после INSERT-а сразу же выполнить запрос

SELECT MAX (id) FROM <table>

?
Приходиться заниматься гадостью — зарабатывать на жизнь честным трудом (Б.Шоу)
Re: Правильные способы узнать id после INSERT в MS SQL 2012
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 18.04.16 07:07
Оценка:
Здравствуйте, Michael7, Вы писали:


M>2) Использовать SCOPE_IDENTITY() Минус тот же. Нет гарантии, что никто не добавил запись.


https://msdn.microsoft.com/ru-ru/library/ms190315(v=sql.120).aspx

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

и солнце б утром не вставало, когда бы не было меня
Отредактировано 18.04.2016 7:08 Serginio1 . Предыдущая версия .
Re[2]: Правильные способы узнать id после INSERT в MS SQL 2012
От: DarkMaster Украина http://www.bdslib.at.ua
Дата: 18.04.16 07:41
Оценка: +1
Здравствуйте, fplab, Вы писали:

F>Что-то мне подсказывает, что тут есть засада, но что если после INSERT-а сразу же выполнить запрос


F>
F>SELECT MAX (id) FROM <table>
F>

F>?

Представь для начала 100 пользователей, одновременно вставляющих данные в таблицу.
WBR, Dmitry Beloshistov AKA [-=BDS=-]
Re[3]: Правильные способы узнать id после INSERT в MS SQL 2012
От: fplab Россия http://fplab.h10.ru http://fplab.blogspot.com/
Дата: 18.04.16 07:46
Оценка:
Здравствуйте, DarkMaster, Вы писали:

DM>Здравствуйте, fplab, Вы писали:


F>>Что-то мне подсказывает, что тут есть засада, но что если после INSERT-а сразу же выполнить запрос


F>>
F>>SELECT MAX (id) FROM <table>
F>>

F>>?

DM>Представь для начала 100 пользователей, одновременно вставляющих данные в таблицу.

Я же и говорил — где-то тут засада
Приходиться заниматься гадостью — зарабатывать на жизнь честным трудом (Б.Шоу)
Re: Правильные способы узнать id после INSERT в MS SQL 2012
От: Olaf Россия  
Дата: 18.04.16 08:30
Оценка: 122 (3) +1
Здравствуйте, Michael7, Вы писали:

M>Вот что стоило разработчикам SQL позволить INSERT возвращать значения автоинкрементируемых полей после вставки? Лишнего геморойства было бы меньше. Пока что вижу три способа узнать значение автоикремента и не знаю какой самый правильный.


M>1) Так сейчас делаю. После вставки сразу SELECT Where по вставленным полям и получаю id записи. Минус: если найденных записей несколько — нет гарантии, что у вставленной записи максимальный номер. Параллельно могла произойти еще одна вставка и вообще у автоинкрементного поля кажется гарантируется только уникальность, но не возрастание. Впрочем, тут могу ошибаться. На практике однако часто это не существенно или не случается.


M>2) Использовать SCOPE_IDENTITY() Минус тот же. Нет гарантии, что никто не добавил запись.


M>3) Триггер на вставку в таблицу, который пишет id в отдельную таблицу. Можно запутаться


M>В принципе есть еще вариант. Отказаться от автоинкремента, но оставить ограничение на уникальность и самому присваивать id, если возникнет ошибка неуникальности, значит, кто-то параллельно добавил и надо просто продолжать добавлять записи с id++ пока не добавится.


M>Вот как корректнее всего даже и не знаю. А может я и вовсе чего-то не понял.


Все как раз наоборот. Свойство Identity гарантирует следующее:

• Each new value is generated based on the current seed & increment.
• Each new value for a particular transaction is different from other concurrent transactions on the table.

А вот уникальность оно не гарантирует. Вы можете самостоятельно изменить параметр Seed и начать использовать значения автоинкремента повторно, т.е. зациклив его.

Не гарантируется так же порядок вставки сгенерированных значений в таблицу, т.е. меньшее значение может быть вставлено позже большего. Чревато это высокой фрагментированностью индекса, если он у вас есть на этом поле, ну и наличием неправильных значений в случае использования подхода, который здесь уже неоднократно упоминался — select max(value) from dbo.Table1

Правильный вариант предложил andrey82
Автор: andrey82
Дата: 16.04.16
через output inserted, особенно если у вас выполняется вставка нескольких записей. Кроме того, этот же вариант одно время рекомендовал Microsoft, после того как была обнаружена проблема возврата некорректных значений при использовании функций @@identity и scope_identity() в параллельных планах запроса версий 2005 и 2008 (You may receive incorrect values when using SCOPE_IDENTITY() and @@IDENTITY). C SP1 эта проблема уже ушла, поэтому вариант со scope_identity() так же рабочий, несмотря на ваши опасения.
Отредактировано 18.04.2016 15:49 Olaf . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.