-
Вопрос тут уже вроде всплывал тут, но в основном касался каких то конкретных СУБД, например Access. Мне же нужен по возможности универсальный вариант, ну пусть хотя бы одинаково работающий в Access, MySQL, MSSQL, Oracle.
Посредством SQL запроса в таблицу добавляется некая запись. Одним из полей таблицы является автоинкрементное поле счетчик (ID).
После добавления записи в таблицу мне нужно получить значение поля ID для этой добавленной записи.
Как в таких случаях обычно поступают? Писать разный код для разных СУБД? Ввести свое доп. поле в которое пихать собственноручно сгенерированное чудо типа GUID и сразу после добавления находить запись по этому полю?
-
> Мне же нужен по возможности универсальный вариант
слишком бессмысленно
хотя иногда может помочь уникальная комбинация записываемых полей, еслиона есть, конечно
-
> Посредством SQL запроса в таблицу добавляется некая запись.
> Одним из полей таблицы является автоинкрементное поле счетчик
> (ID).
> После добавления записи в таблицу мне нужно получить значение
> поля ID для этой добавленной записи.
1. Сам тип автоинкримента может быть разным (int и bigint, serial и bigserial и т.п.).
2. Его (автоинкримента) может и не быть как такового в СУБД.
3. И GUID СУБД тоже может не уметь генерить (например, Postgres в поставке по-умолчанию не умеет, т.к. есть несколько способов).
Я бы в такой ситуации на клиенте какое-нибудь уникальное значение генерил.
-
> слишком бессмысленно
Может и бессмысленно, но хотелось бы абстрагировать несложное ПО от конкретной СУБД. Или хотя бы свести к минимуму переделки под другую СУБД.
> хотя иногда может помочь уникальная комбинация записываемых
> полей, еслиона есть, конечно
такая мысль была, но комбинации полей не уникальны.
-
> Ega23 © (04.09.08 12:12) [2]
> 1. Сам тип автоинкримента может быть разным (int и bigint,
> serial и bigserial и т.п.).
Ну int или подобный есть везде вроде.
> 2. Его (автоинкримента) может и не быть как такового в СУБД.
Я не замахиваюсь на вообще все СУБД. В тех что я написал есть по крайней мере.
> 3. И GUID СУБД тоже может не уметь генерить (например, Postgres
> в поставке по-умолчанию не умеет, т.к. есть несколько способов).
>
Так сам генерить буду и в запрос буду пихать.
> Я бы в такой ситуации на клиенте какое-нибудь уникальное
> значение генерил.
Да я помню ветку про GUID-ы. Пока рассматриваю как основной вариант. Хотя совпадения возможные совсем не радуют.
-
DVM © (04.09.08 12:03)
наверное такой:
после вставки
select max(ID) from mytable
-
> Писать разный код для разных СУБД?
Да
-
> stas © (04.09.08 12:22) [5]
> select max(ID) from mytable
>
А если между моей вставкой и последующим выполнение этого запроса другой клиент добавит еще запись? Я получу не свой ID.
-
> Ввести свое доп. поле в которое пихать собственноручно сгенерированное
> чудо типа GUID и сразу после добавления находить запись
> по этому полю?
А ... зачем при этом "автоинкрементное поле счетчик" ?
-
> А ... зачем при этом "автоинкрементное поле счетчик" ?
>
Тогда ID собственно станет не нужен, использоваться будет это дополнительное поле в качестве ключевого.
-
> stas © (04.09.08 12:22) [5]
>
> DVM © (04.09.08 12:03)
> наверное такой:
> после вставки
> select max(ID) from mytable
Расстрелять из пулемёта за такое.
Кстати, он может быть и не Max, то таки быть уникальным. Об этом не думал?
-
> Кстати, он может быть и не Max, но таки быть уникальным.
> Об этом не думал?
-
Может быть сделать некую одинаковую функцию во всех СУБД, которая будет работать с таблицей, хранящей текущие идентификаторы всех талиц в БД? Хотя наверное конкуренция за эту таблицу получится сумашедшая в приличных размеров системе.
-
> Sergey13 © (04.09.08 12:32) [12]
>
> Может быть сделать некую одинаковую функцию во всех СУБД,
> которая будет работать с таблицей, хранящей текущие идентификаторы
> всех талиц в БД?
Не очень понял. Поясни.
-
> Да я помню ветку про GUID-ы. Пока рассматриваю как основной
> вариант. Хотя совпадения возможные совсем не радуют.
Там GUID-ы (точнее - аналог) совсем по-другой причине использовались: нужна была уникальная идентификация сущности не в рамках одного комплекса, а вообще, глобально.
-
> хотелось бы абстрагировать несложное ПО от конкретной СУБД
если это несложное по однопользовательское, то очень осторожно можно использовать MAX, хотя любое однопользовательское имеет тенденцию к переходу в многопользовательскую
но тогда появляется желание выжать больше из СУБД, но на абстракной СУБД больше выжать нельзя, появляется специфика, а тут уже никакой абстрактности, сплошная конкретика
-
> Не очень понял. Поясни.
Ну что-то типа интербэйзного генератора
-
> Хотя наверное конкуренция за эту таблицу получится сумашедшая
> в приличных размеров системе.
"Каждой твари по паре" :)
-
> Правильный$Вася (04.09.08 12:37) [15]
Все верно. ПО относительно несложное, но многопользовательское все же.
-
> Может быть сделать некую одинаковую функцию во всех СУБД
не все субд поддерживают функции, да и способ их вызова различен
-
> Все верно. ПО относительно несложное, но многопользовательское
> все же.
выноси общение с СУБД на уровень абстракции. Для каждой - реализация своя; то, что с этой абстракцией работает, про СУБД ничего не знает.
В конце-концов, ключевое поле на клиенте - вещь вообще абстрактнее некуда.
-
> Ega23 © (04.09.08 12:51) [20]
да, по сути - нужен модуль-посредник, который для каждой субд будет свой, а интерфейс к нему от основной функциональности - единый
-
> да, по сути - нужен модуль-посредник, который для каждой
> субд будет свой, а интерфейс к нему от основной функциональности
> - единый
Угу.
-
>DVM © (04.09.08 12:25) [7]
Заключить в одну транзакцию.
>Ega23 © (04.09.08 12:32) [11]
может конечно быть минимальным
>Ega23 © (04.09.08 12:31) [10]
>Расстрелять из пулемёта за такое.
Возможно, но это единственный способ, который будет работать с любой БД.
-
> Возможно, но это единственный способ, который будет работать
> с любой БД.
ты бредишь
-
> [13] DVM © (04.09.08 12:36)
> Не очень понял. Поясни.
Ну в принципе
> [16] Ega23 © (04.09.08 12:38)
> Ну что-то типа интербэйзного генератора
Есть таблица с двумя полями Table_name и Current_Id. Пишется функция, которая на входе получает имя таблицы а на выходе отдает текущее знгачение+1, меняя содержимое соответствующего поля. Все ключи заполняются через эту функцию. Опросив текущее значение получаешь искомое.
Но это не решение - это идея для решения. Потому что это надо очень задуматься о конкуренции на эту таблицу.
-
> может конечно быть минимальным
1. Ты удивишься, но я тебе могу написать запрос для MSSQL, который будет вставлять значение в "дырку" для Identity-поля.
2. Ключ и не автоинкриментом может быть. Но при этом не перестаёт быть ключом.
-
> ты бредишь
+1
-
> Sergey13 © (04.09.08 13:09) [25]
Теперь ясно, спасибо.
-
Ega23 © (04.09.08 13:18) [26]
1. Ты уверен что scope_identity() в этом варианте тебе вернет верное значение?
2.
> Одним из полей таблицы является автоинкрементное поле
> счетчик (ID).
> После добавления записи в таблицу мне нужно получить значение
> поля ID для этой добавленной записи.
-
> stas © (04.09.08 13:28) [29]
это автоинкрементное поле счетчик (ID) только в голове автора, т.к. СУБД абстрактная, то это не более, чем идея, а не способ реализации
-
> 1. Ты уверен что scope_identity() в этом варианте тебе вернет
> верное значение?
А ты уверен, что scope_identity() тебе вообще что-то вернёт в этом случае?
смотри в сторону SET IDENTITY_INSERT ON/OFF
-
> DVM © (04.09.08 12:03)
В данных условиях я бы генерил уникальное значение на клиенте. (Ну понятное дело, что не 100% уникальное:))
> Игорь Шевченко © (04.09.08 13:06) [24]
> ты бредишь
Причем делает это перманентно в на разные темы...
-
Ega23 © (04.09.08 13:31) [31]
Ну, так тогда о чем вообще разговор?
Узнать в любой базе последний вставленый ID?
а если было сразу вставлено 5 строк?
а как решит проблему модуль-посредник если этот ID надо использовать в дальнеших инструкциях запроса?
И насколько сложная и ответственная задача чтобы это все городить?
Johnmen © (04.09.08 13:34) [32]
генеальное решение. :-D
-
> а как решит проблему модуль-посредник если этот ID надо
> использовать в дальнеших инструкциях запроса?
Если надо использовать - то используй, тебе никто не мешает.
declare @ID uniqueidentifier;
Set @ID=:ID
Set NoCount On
Insert into Table1 (ID, .....) Values (@ID, .....);
Insert into Table2 (ID, .....) Values (@ID, .....);
/*
Используем @ID так, как хочеццо.
*/
-
Ega23 © (04.09.08 14:31)
[34]Типа такого:
declare @ID int
Insert into...
Set @ID=scope_identity()
Insert into ... Values (@ID)
-
> Типа такого:
Что типа такого? Ещё раз: я могу в таблицу с Identity-полем вставить в "дырку" ключевое значение, отключив на время Identity. И твой скрипт в этом случае:
а) пойдёт лесом.
б) даже если и не пойдёт, то будет работать только под mssql.
-
Ega23 © (04.09.08 14:45) [36]
1. Опять же, что автору требуется?
2. Какой скрипт не пойдет лесом?
-
> stas © (04.09.08 16:26) [37]
> Опять же, что автору требуется?
Ты не только бредишь в ответах, но и принципиально не читаешь постановку вопроса ветки?
Или же первое - результат второго?
Просто интересно...
-
Johnmen © (04.09.08 16:34) [38]
более глупого поста чем Johnmen © (04.09.08 13:34) [32]
в этой ветке небыло.
-
> более глупого поста чем Johnmen © (04.09.08 13:34) [32]
> в этой ветке небыло.
Вообще-то он как бы по делу спросил...
-
Жаль, что нельзя вставить в цитату все посты в этой ветке...
Куда катится мир? До чего довел планету этот фигляр Пэжэ?!!
> stas © (04.09.08 16:40) [39]
>
> Johnmen © (04.09.08 16:34) [38]
> более глупого поста чем Johnmen © (04.09.08 13:34) [32]
> в этой ветке небыло.
БЫЛО!!! Вот это:
> stas © (04.09.08 12:22) [5]
>
> DVM © (04.09.08 12:03)
> наверное такой:
> после вставки
> select max(ID) from mytable
Хотя они друг друга стоят.
-
> stas © (04.09.08 16:40) [39]
> Johnmen © (04.09.08 16:34) [38]более глупого поста чем
> Johnmen © (04.09.08 13:34) [32]в этой ветке небыло.
Это ты так думаешь на основании своих убогих знаний и нулевого опыта.
> Курдль (04.09.08 16:52) [41]
> Хотя они друг друга стоят.
Не стОит право ровнять моё предложение [32] с [5].
А то могу подумать грустное про тебя...:)
-
пошли разборки, пора закрываться
-
> Хотя они друг друга стоят.
А в чём проблема генерации ID на клиенте? Искренне не понимаю...
-
Какой "клиент" может дать вам гарантированно уникальный идентификатор (не GUID)?
Какой запрос гарантированно защитит вас от многопользовательской коллизии?
Зачем СУБД городили все эти генераторы, последовательности, автоинкременты и т.п.?
-
> Какой "клиент" может дать вам гарантированно уникальный
> идентификатор (не GUID)?
А этого и не требуется :)
> Какой запрос гарантированно защитит вас от многопользовательской коллизии?
Не запрос. А возвращаемая сервером ошибка.
> Зачем СУБД городили все эти генераторы, последовательности,
> автоинкременты и т.п.?
Перечитай постановку вопроса автора ветки.
ЗЫ
Начинаешь огорчать...:(
-
> Какой "клиент" может дать вам гарантированно уникальный
> идентификатор (не GUID)?
Кстати, и GUID не гарантирует...
-
> Johnmen © (04.09.08 17:12) [46]
> Перечитай постановку вопроса автора ветки.
Я именно поэтому привел цитату из Кин-дза-дзы.
Ну, автор решил осчастливить мир каким-нибудь компонентом, который "может все".
А вы-то что? Почему в первом же посте не сказали, что ЭТО НЕВОЗМОЖНО.
Почитайте спец. литературу по СУБД и найдите там "альтернативные" варианты получения уникальных идентификаторов.
-
> Почему в первом же посте не сказали, что ЭТО НЕВОЗМОЖНО
да ну? я ж сказал - бессмысленно
-
1. Гарантирует уникальность автоинкримент
2. определить последнию вставленную запись универсальным методом можно
select max(ID) from mytable в рамках одной транзакции
и без извращений описаных в Ega23 © (04.09.08 13:31) [31]
если так рассуждать можно любой метод завалить
3. Давать глупые советы и доказывать что они умные еще глупее тем более если у тебя в анкете буква M
4. чем глупее [5] чем [39] обоснуй пожалуйста
5. Попробуйте доказать обратное 1 и 2.
-
> 1. Гарантирует уникальность автоинкримент
1. Не гарантирует (для MSSQL способы "ломания" я уже приводил. Есть и другие).
2. Есть далеко не везде.
3. select max(ID) Если уж взялся такое писать, то пиши как положено:
select IsNull(max(ID) + 1, 1)
-
> определить последнию вставленную запись универсальным методом
> можноselect max(ID) from mytable в рамках одной транзакции
только в однопользовательском случае, не бывает междупользовательских транзакций
в остальных случаях последняя вставленная может быть совсем не твоя
мало того, если инкремент делать -1, то и не max вовсе нужно использовать
-
Ega23 © (04.09.08 17:43) [51]
зачем +1 это же не будет ID последней вставленной записи.
-
> зачем +1 это же не будет ID последней вставленной записи.
Зачем мне ID "последней вставленной записи"?
И что будет, если таблица пустая?
-
> Зачем мне ID "последней вставленной записи"?
Олег, ты заголовок темы забыл :)
а зачем - так хотя бы для того, чтобы использовать его в других таблицах в рамках транзакции
> И что будет, если таблица пустая?
вряд ли она будет пустая, если запись только что добавили (хотя варианты есть, конечно)
-
> Олег, ты заголовок темы забыл :)
> а зачем - так хотя бы для того, чтобы использовать его в
> других таблицах в рамках транзакции
Declare @ID int;
Select @ID=IsNull(Max(ID) + 1, 1) from Table;
Insert into Table (ID, ....) Values (@ID, ...)
Только так, по-другому низя....
-
Ega23 © (04.09.08 18:39)
[56]я предлагал так:
Declare @ID int;
Insert into Table (....) Values ( ...)
Select @ID=select Max(ID) from Table;
-
Правильный$Вася (04.09.08 17:43) [52]
> begin tran
> Declare @ID int
> Insert into Table (....) Values ( ...)
> Select @ID=select Max(ID) from Table;
> commit tran
Это пройдет в рамках одной транзакции, что исключает между инструкциями выполнение другой транзакции
-
> stas © (04.09.08 21:58) [58]
дудки
другая транзакция (от другого подключения) может запросто закончиться где-нить между Insert и select, в результате ты увидишь чужой id
-
Правильный$Вася (04.09.08 22:14)
[59]Может, есть уровни блокировки, хотя это уже будет не универсальный метод.
сократить вероятность можно добавлением условия и перечислением в условии всех вставленных полей т.е.
Insert into Table (F1,F2,F3) Values (@F1,@F2,@F3)
Select select Max(ID) from Table WHERE F1=@F1 AND F2=@F2 AND F3=@F3
В некотрых случаях возможность получения чужого ID снижатся до 0, в некоторых остается. Так же как и в любом из предложеных методов.
-
> сократить вероятность можно
можно
но при наличии отличной от нуля вероятности такой метод можно смело сливать в унитаз
-
> Мне же нужен по возможности универсальный вариант, ну пусть
> хотя бы одинаково работающий в Access, MySQL, MSSQL, Oracle.
>
для перечисленных СУБД оптимального универсального варианта нет.
-
еще один универсал? :-)