Сообщение Re: Правильные способы узнать id после INSERT в MS SQL 2012 от 18.04.2016 8:30
Изменено 18.04.2016 15:49 Olaf
Здравствуйте, Michael7, Вы писали:
M>Вот что стоило разработчикам SQL позволить INSERT возвращать значения автоинкрементируемых полей после вставки? Лишнего геморойства было бы меньше. Пока что вижу три способа узнать значение автоикремента и не знаю какой самый правильный.
M>1) Так сейчас делаю. После вставки сразу SELECT Where по вставленным полям и получаю id записи. Минус: если найденных записей несколько — нет гарантии, что у вставленной записи максимальный номер. Параллельно могла произойти еще одна вставка и вообще у автоинкрементного поля кажется гарантируется только уникальность, но не возрастание. Впрочем, тут могу ошибаться. На практике однако часто это не существенно или не случается.
M>2) Использовать SCOPE_IDENTITY() Минус тот же. Нет гарантии, что никто не добавил запись.
M>3) Триггер на вставку в таблицу, который пишет id в отдельную таблицу. Можно запутаться
M>В принципе есть еще вариант. Отказаться от автоинкремента, но оставить ограничение на уникальность и самому присваивать id, если возникнет ошибка неуникальности, значит, кто-то параллельно добавил и надо просто продолжать добавлять записи с id++ пока не добавится.
M>Вот как корректнее всего даже и не знаю. А может я и вовсе чего-то не понял.
Все как раз наоборот. Свойство Identity гарантирует следующее:
Не гарантируется так же порядок вставки сгенерированных значений в таблицу, т.е. меньшее значение может быть вставлено позже большего. Чревато это высокой фрагментированностью индекса, если он у вас есть на этом поле, ну и наличием неправильных значений в случае использования подхода, который здесь уже неоднократно упоминался — select max(value) from dbo.Table1
Правильный вариант вам предложил andrey82, особенно если у вас выполняется вставка нескольких записей. Кроме того, этот же вариант одно время рекомендовал Microsoft, после того как была обнаружена проблема возврата некорректных значений при использовании функций @@identity и scope_identity() в параллельных планах запроса версий 2005 и 2008 (You may receive incorrect values when using SCOPE_IDENTITY() and @@IDENTITY). C SP1 эта проблема уже ушла, поэтому вариант со scope_identity() так же рабочий, несмотря на ваши опасения.
M>Вот что стоило разработчикам SQL позволить INSERT возвращать значения автоинкрементируемых полей после вставки? Лишнего геморойства было бы меньше. Пока что вижу три способа узнать значение автоикремента и не знаю какой самый правильный.
M>1) Так сейчас делаю. После вставки сразу SELECT Where по вставленным полям и получаю id записи. Минус: если найденных записей несколько — нет гарантии, что у вставленной записи максимальный номер. Параллельно могла произойти еще одна вставка и вообще у автоинкрементного поля кажется гарантируется только уникальность, но не возрастание. Впрочем, тут могу ошибаться. На практике однако часто это не существенно или не случается.
M>2) Использовать SCOPE_IDENTITY() Минус тот же. Нет гарантии, что никто не добавил запись.
M>3) Триггер на вставку в таблицу, который пишет id в отдельную таблицу. Можно запутаться
M>В принципе есть еще вариант. Отказаться от автоинкремента, но оставить ограничение на уникальность и самому присваивать id, если возникнет ошибка неуникальности, значит, кто-то параллельно добавил и надо просто продолжать добавлять записи с id++ пока не добавится.
M>Вот как корректнее всего даже и не знаю. А может я и вовсе чего-то не понял.
Все как раз наоборот. Свойство Identity гарантирует следующее:
А вот уникальность оно не гарантирует. Вы можете самостоятельно изменить параметр Seed и начать использовать значения автоинкремента повторно, т.е. зациклив его.• 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.
Не гарантируется так же порядок вставки сгенерированных значений в таблицу, т.е. меньшее значение может быть вставлено позже большего. Чревато это высокой фрагментированностью индекса, если он у вас есть на этом поле, ну и наличием неправильных значений в случае использования подхода, который здесь уже неоднократно упоминался — select max(value) from dbo.Table1
Правильный вариант вам предложил andrey82, особенно если у вас выполняется вставка нескольких записей. Кроме того, этот же вариант одно время рекомендовал Microsoft, после того как была обнаружена проблема возврата некорректных значений при использовании функций @@identity и scope_identity() в параллельных планах запроса версий 2005 и 2008 (You may receive incorrect values when using SCOPE_IDENTITY() and @@IDENTITY). C SP1 эта проблема уже ушла, поэтому вариант со scope_identity() так же рабочий, несмотря на ваши опасения.
Re: Правильные способы узнать id после INSERT в MS SQL 2012
Здравствуйте, Michael7, Вы писали:
M>Вот что стоило разработчикам SQL позволить INSERT возвращать значения автоинкрементируемых полей после вставки? Лишнего геморойства было бы меньше. Пока что вижу три способа узнать значение автоикремента и не знаю какой самый правильный.
M>1) Так сейчас делаю. После вставки сразу SELECT Where по вставленным полям и получаю id записи. Минус: если найденных записей несколько — нет гарантии, что у вставленной записи максимальный номер. Параллельно могла произойти еще одна вставка и вообще у автоинкрементного поля кажется гарантируется только уникальность, но не возрастание. Впрочем, тут могу ошибаться. На практике однако часто это не существенно или не случается.
M>2) Использовать SCOPE_IDENTITY() Минус тот же. Нет гарантии, что никто не добавил запись.
M>3) Триггер на вставку в таблицу, который пишет id в отдельную таблицу. Можно запутаться
M>В принципе есть еще вариант. Отказаться от автоинкремента, но оставить ограничение на уникальность и самому присваивать id, если возникнет ошибка неуникальности, значит, кто-то параллельно добавил и надо просто продолжать добавлять записи с id++ пока не добавится.
M>Вот как корректнее всего даже и не знаю. А может я и вовсе чего-то не понял.
Все как раз наоборот. Свойство Identity гарантирует следующее:
Не гарантируется так же порядок вставки сгенерированных значений в таблицу, т.е. меньшее значение может быть вставлено позже большего. Чревато это высокой фрагментированностью индекса, если он у вас есть на этом поле, ну и наличием неправильных значений в случае использования подхода, который здесь уже неоднократно упоминался — select max(value) from dbo.Table1
Правильный вариант предложил andrey82
M>Вот что стоило разработчикам SQL позволить INSERT возвращать значения автоинкрементируемых полей после вставки? Лишнего геморойства было бы меньше. Пока что вижу три способа узнать значение автоикремента и не знаю какой самый правильный.
M>1) Так сейчас делаю. После вставки сразу SELECT Where по вставленным полям и получаю id записи. Минус: если найденных записей несколько — нет гарантии, что у вставленной записи максимальный номер. Параллельно могла произойти еще одна вставка и вообще у автоинкрементного поля кажется гарантируется только уникальность, но не возрастание. Впрочем, тут могу ошибаться. На практике однако часто это не существенно или не случается.
M>2) Использовать SCOPE_IDENTITY() Минус тот же. Нет гарантии, что никто не добавил запись.
M>3) Триггер на вставку в таблицу, который пишет id в отдельную таблицу. Можно запутаться
M>В принципе есть еще вариант. Отказаться от автоинкремента, но оставить ограничение на уникальность и самому присваивать id, если возникнет ошибка неуникальности, значит, кто-то параллельно добавил и надо просто продолжать добавлять записи с id++ пока не добавится.
M>Вот как корректнее всего даже и не знаю. А может я и вовсе чего-то не понял.
Все как раз наоборот. Свойство Identity гарантирует следующее:
А вот уникальность оно не гарантирует. Вы можете самостоятельно изменить параметр Seed и начать использовать значения автоинкремента повторно, т.е. зациклив его.• 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.
Не гарантируется так же порядок вставки сгенерированных значений в таблицу, т.е. меньшее значение может быть вставлено позже большего. Чревато это высокой фрагментированностью индекса, если он у вас есть на этом поле, ну и наличием неправильных значений в случае использования подхода, который здесь уже неоднократно упоминался — 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() так же рабочий, несмотря на ваши опасения.Дата: 16.04.16