Конференция "Базы" » ID последней добавленной записи [D7, любая СУБД]
 
  • DVM © (04.09.08 12:03) [0]
    Вопрос тут уже вроде всплывал тут, но в основном касался каких то конкретных СУБД, например Access. Мне же нужен по возможности универсальный вариант, ну пусть хотя бы одинаково работающий в Access, MySQL, MSSQL, Oracle.

    Посредством SQL запроса в таблицу добавляется некая запись. Одним из полей таблицы является автоинкрементное поле счетчик (ID).
    После добавления записи в таблицу мне нужно получить значение поля ID для этой добавленной записи.

    Как в таких случаях обычно поступают? Писать разный код для разных СУБД? Ввести свое доп. поле в которое пихать собственноручно сгенерированное чудо типа GUID и сразу после добавления находить запись по этому полю?
  • Правильный$Вася (04.09.08 12:07) [1]

    > Мне же нужен по возможности универсальный вариант

    слишком бессмысленно
    хотя иногда может помочь уникальная комбинация записываемых полей, еслиона есть, конечно
  • Ega23 © (04.09.08 12:12) [2]

    > Посредством SQL запроса в таблицу добавляется некая запись.
    >  Одним из полей таблицы является автоинкрементное поле счетчик
    > (ID).
    > После добавления записи в таблицу мне нужно получить значение
    > поля ID для этой добавленной записи.


    1. Сам тип автоинкримента может быть разным (int  и bigint, serial и bigserial и т.п.).
    2. Его (автоинкримента) может и не быть как такового в СУБД.
    3. И GUID СУБД тоже может не уметь генерить (например, Postgres в поставке по-умолчанию не умеет, т.к. есть несколько способов).

    Я бы в такой ситуации на клиенте какое-нибудь уникальное значение генерил.
  • DVM © (04.09.08 12:14) [3]

    > слишком бессмысленно

    Может и бессмысленно, но хотелось бы абстрагировать несложное ПО от конкретной СУБД. Или хотя бы свести к минимуму переделки под другую СУБД.


    > хотя иногда может помочь уникальная комбинация записываемых
    > полей, еслиона есть, конечно

    такая мысль была, но комбинации полей не уникальны.
  • DVM © (04.09.08 12:18) [4]

    > Ega23 ©   (04.09.08 12:12) [2]


    > 1. Сам тип автоинкримента может быть разным (int  и bigint,
    >  serial и bigserial и т.п.).

    Ну int или подобный есть везде вроде.


    > 2. Его (автоинкримента) может и не быть как такового в СУБД.

    Я не замахиваюсь на вообще все СУБД. В тех что я написал есть по крайней мере.


    > 3. И GUID СУБД тоже может не уметь генерить (например, Postgres
    > в поставке по-умолчанию не умеет, т.к. есть несколько способов).
    >

    Так сам генерить буду и в запрос буду пихать.


    > Я бы в такой ситуации на клиенте какое-нибудь уникальное
    > значение генерил.

    Да я помню ветку про GUID-ы. Пока рассматриваю как основной вариант. Хотя совпадения возможные совсем не радуют.
  • stas © (04.09.08 12:22) [5]
    DVM ©   (04.09.08 12:03)
    наверное такой:
    после вставки
    select max(ID) from mytable
  • Игорь Шевченко © (04.09.08 12:24) [6]

    > Писать разный код для разных СУБД?


    Да
  • DVM © (04.09.08 12:25) [7]

    > stas ©   (04.09.08 12:22) [5]


    > select max(ID) from mytable
    >

    А если между моей вставкой и последующим выполнение этого запроса другой клиент добавит еще запись? Я получу не свой ID.
  • b z (04.09.08 12:28) [8]

    > Ввести свое доп. поле в которое пихать собственноручно сгенерированное
    > чудо типа GUID и сразу после добавления находить запись
    > по этому полю?
    А ... зачем при этом "автоинкрементное поле счетчик" ?
  • DVM © (04.09.08 12:31) [9]

    > А ... зачем при этом "автоинкрементное поле счетчик" ?
    >

    Тогда ID собственно станет не нужен, использоваться будет это дополнительное поле в качестве ключевого.
  • Ega23 © (04.09.08 12:31) [10]

    > stas ©   (04.09.08 12:22) [5]
    >
    > DVM ©   (04.09.08 12:03)
    > наверное такой:
    > после вставки
    > select max(ID) from mytable


    Расстрелять из пулемёта за такое.
    Кстати, он может быть и не Max, то таки быть уникальным. Об этом не думал?
  • Ega23 © (04.09.08 12:32) [11]

    > Кстати, он может быть и не Max, но таки быть уникальным.
    >  Об этом не думал?
  • Sergey13 © (04.09.08 12:32) [12]
    Может быть сделать некую одинаковую функцию во всех СУБД, которая будет работать с таблицей, хранящей текущие идентификаторы всех талиц в БД? Хотя наверное конкуренция за эту таблицу получится сумашедшая в приличных размеров системе.
  • DVM © (04.09.08 12:36) [13]

    > Sergey13 ©   (04.09.08 12:32) [12]
    >
    > Может быть сделать некую одинаковую функцию во всех СУБД,
    >  которая будет работать с таблицей, хранящей текущие идентификаторы
    > всех талиц в БД?

    Не очень понял. Поясни.
  • Ega23 © (04.09.08 12:37) [14]

    > Да я помню ветку про GUID-ы. Пока рассматриваю как основной
    > вариант. Хотя совпадения возможные совсем не радуют.


    Там GUID-ы (точнее - аналог) совсем по-другой причине использовались: нужна была уникальная идентификация сущности не в рамках одного комплекса, а вообще, глобально.
  • Правильный$Вася (04.09.08 12:37) [15]

    >  хотелось бы абстрагировать несложное ПО от конкретной СУБД

    если это несложное по однопользовательское, то очень осторожно можно использовать MAX, хотя любое однопользовательское имеет тенденцию к переходу в многопользовательскую
    но тогда появляется желание выжать больше из СУБД, но на абстракной СУБД больше выжать нельзя, появляется специфика, а тут уже никакой абстрактности, сплошная конкретика
  • Ega23 © (04.09.08 12:38) [16]

    > Не очень понял. Поясни.


    Ну что-то типа интербэйзного генератора
  • b z (04.09.08 12:41) [17]

    > Хотя наверное конкуренция за эту таблицу получится сумашедшая
    > в приличных размеров системе.
    "Каждой твари по паре" :)
  • DVM © (04.09.08 12:44) [18]

    > Правильный$Вася   (04.09.08 12:37) [15]

    Все верно. ПО относительно несложное, но многопользовательское все же.
  • Правильный$Вася (04.09.08 12:45) [19]

    > Может быть сделать некую одинаковую функцию во всех СУБД

    не все субд поддерживают функции, да и способ их вызова различен
  • Ega23 © (04.09.08 12:51) [20]

    > Все верно. ПО относительно несложное, но многопользовательское
    > все же.


    выноси общение с СУБД на уровень абстракции. Для каждой - реализация своя; то, что с этой абстракцией работает, про СУБД ничего не знает.
    В конце-концов, ключевое поле на клиенте - вещь вообще абстрактнее некуда.
  • Правильный$Вася (04.09.08 12:58) [21]

    > Ega23 ©   (04.09.08 12:51) [20]

    да, по сути - нужен модуль-посредник, который для каждой субд будет свой, а интерфейс к нему от основной функциональности - единый
  • Ega23 © (04.09.08 13:00) [22]

    > да, по сути - нужен модуль-посредник, который для каждой
    > субд будет свой, а интерфейс к нему от основной функциональности
    > - единый


    Угу.
  • stas © (04.09.08 13:05) [23]
    >DVM ©   (04.09.08 12:25) [7]
    Заключить в одну транзакцию.

    >Ega23 ©   (04.09.08 12:32) [11]
    может конечно быть минимальным

    >Ega23 ©   (04.09.08 12:31) [10]
    >Расстрелять из пулемёта за такое.
    Возможно, но это единственный  способ, который будет работать с любой БД.
  • Игорь Шевченко © (04.09.08 13:06) [24]

    > Возможно, но это единственный  способ, который будет работать
    > с любой БД.


    ты бредишь
  • Sergey13 © (04.09.08 13:09) [25]
    > [13] DVM ©   (04.09.08 12:36)
    > Не очень понял. Поясни.

    Ну в принципе

    > [16] Ega23 ©   (04.09.08 12:38)
    > Ну что-то типа интербэйзного генератора

    Есть таблица с двумя полями Table_name и Current_Id. Пишется функция, которая на входе получает имя таблицы а на выходе отдает текущее знгачение+1, меняя содержимое соответствующего поля. Все ключи заполняются через эту функцию. Опросив текущее значение получаешь искомое.
    Но это не решение - это идея для решения. Потому что это надо очень задуматься о конкуренции на эту таблицу.
  • Ega23 © (04.09.08 13:18) [26]

    > может конечно быть минимальным


    1. Ты удивишься, но я тебе могу написать запрос для MSSQL, который будет вставлять значение в "дырку" для Identity-поля.
    2. Ключ и не автоинкриментом может быть. Но при этом не перестаёт быть ключом.
  • Ega23 © (04.09.08 13:19) [27]

    > ты бредишь


    +1
  • DVM © (04.09.08 13:24) [28]

    > Sergey13 ©   (04.09.08 13:09) [25]

    Теперь ясно, спасибо.
  • stas © (04.09.08 13:28) [29]
    Ega23 ©   (04.09.08 13:18) [26]

    1. Ты уверен что scope_identity() в этом варианте тебе вернет верное значение?
    2.

    > Одним из полей таблицы является автоинкрементное поле
    > счетчик (ID)
    .
    > После добавления записи в таблицу мне нужно получить значение
    > поля ID для этой добавленной записи.
  • Правильный$Вася (04.09.08 13:29) [30]

    > stas ©   (04.09.08 13:28) [29]

    это автоинкрементное поле счетчик (ID) только в голове автора, т.к. СУБД абстрактная, то это не более, чем идея, а не способ реализации
  • Ega23 © (04.09.08 13:31) [31]

    > 1. Ты уверен что scope_identity() в этом варианте тебе вернет
    > верное значение?


    А ты уверен, что scope_identity() тебе вообще что-то вернёт в этом случае?
    смотри в сторону SET IDENTITY_INSERT ON/OFF
  • Johnmen © (04.09.08 13:34) [32]

    > DVM ©   (04.09.08 12:03) 

    В данных условиях я бы генерил уникальное значение на клиенте. (Ну понятное дело, что не 100% уникальное:))

    > Игорь Шевченко ©   (04.09.08 13:06) [24]
    > ты бредишь

    Причем делает это перманентно в на разные темы...
  • stas © (04.09.08 13:49) [33]
    Ega23 ©   (04.09.08 13:31) [31]
    Ну, так тогда о чем вообще разговор?
    Узнать в любой базе последний вставленый ID?  
    а если было сразу вставлено 5 строк?
    а как решит проблему модуль-посредник если этот ID надо использовать в дальнеших инструкциях запроса?
    И насколько сложная и ответственная задача чтобы это все городить?
    Johnmen ©   (04.09.08 13:34) [32]
    генеальное решение. :-D
  • Ega23 © (04.09.08 14:31) [34]

    > а как решит проблему модуль-посредник если этот ID надо
    > использовать в дальнеших инструкциях запроса?


    Если надо использовать - то используй, тебе никто не мешает.

    declare @ID uniqueidentifier;
    Set @ID=:ID
    Set NoCount On

    Insert into Table1 (ID, .....) Values (@ID, .....);
    Insert into Table2 (ID, .....) Values (@ID, .....);
    /*
     Используем @ID так, как хочеццо.

    */

  • stas © (04.09.08 14:34) [35]
    Ega23 ©   (04.09.08 14:31) [34]

    Типа такого:
    declare @ID  int
    Insert into...
    Set @ID=scope_identity()

    Insert into ... Values (@ID)

  • Ega23 © (04.09.08 14:45) [36]

    > Типа такого:


    Что типа такого? Ещё раз: я могу в таблицу с Identity-полем вставить в "дырку" ключевое значение, отключив на время Identity. И твой скрипт в этом случае:
    а) пойдёт лесом.
    б) даже если и не пойдёт, то будет работать только под mssql.
  • stas © (04.09.08 16:26) [37]
    Ega23 ©   (04.09.08 14:45) [36]

    1. Опять же,  что автору требуется?
    2. Какой скрипт не пойдет лесом?
  • Johnmen © (04.09.08 16:34) [38]

    > stas ©   (04.09.08 16:26) [37]
    > Опять же,  что автору требуется?

    Ты не только бредишь в ответах, но и принципиально не читаешь постановку вопроса ветки?
    Или же первое - результат второго?
    Просто интересно...
  • stas © (04.09.08 16:40) [39]
    Johnmen ©   (04.09.08 16:34) [38]
    более глупого поста чем Johnmen ©   (04.09.08 13:34) [32]
    в этой ветке небыло.
  • Ega23 © (04.09.08 16:46) [40]

    > более глупого поста чем Johnmen ©   (04.09.08 13:34) [32]
    > в этой ветке небыло.


    Вообще-то он как бы по делу спросил...
  • Курдль (04.09.08 16:52) [41]
    Жаль, что нельзя вставить в цитату все посты в этой ветке...
    Куда катится мир? До чего довел планету этот фигляр Пэжэ?!!


    > 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

    Хотя они друг друга стоят.
  • Johnmen © (04.09.08 16:57) [42]

    > 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].
    А то могу подумать грустное про тебя...:)
  • Правильный$Вася (04.09.08 17:01) [43]
    пошли разборки, пора закрываться
  • Ega23 © (04.09.08 17:01) [44]

    > Хотя они друг друга стоят.


    А в чём проблема генерации ID на клиенте? Искренне не понимаю...
  • Курдль (04.09.08 17:08) [45]
    Какой "клиент" может дать вам гарантированно уникальный идентификатор (не GUID)?
    Какой запрос гарантированно защитит вас от многопользовательской коллизии?

    Зачем СУБД городили все эти генераторы, последовательности, автоинкременты и т.п.?
  • Johnmen © (04.09.08 17:12) [46]

    > Какой "клиент" может дать вам гарантированно уникальный
    > идентификатор (не GUID)?

    А этого и не требуется :)

    > Какой запрос гарантированно защитит вас от многопользовательской  коллизии?

    Не запрос. А возвращаемая сервером ошибка.

    > Зачем СУБД городили все эти генераторы, последовательности,
    >  автоинкременты и т.п.?

    Перечитай постановку вопроса автора ветки.

    ЗЫ
    Начинаешь огорчать...:(
  • Johnmen © (04.09.08 17:13) [47]
    > Какой "клиент" может дать вам гарантированно уникальный
    > идентификатор (не GUID)?
    Кстати, и GUID не гарантирует...
  • Курдль (04.09.08 17:27) [48]

    > Johnmen ©   (04.09.08 17:12) [46]
    > Перечитай постановку вопроса автора ветки.


    Я именно поэтому привел цитату из Кин-дза-дзы.
    Ну, автор решил осчастливить мир каким-нибудь компонентом, который "может все".
    А вы-то что? Почему в первом же посте не сказали, что ЭТО НЕВОЗМОЖНО.
    Почитайте спец. литературу по СУБД и найдите там "альтернативные" варианты получения уникальных идентификаторов.
  • Правильный$Вася (04.09.08 17:31) [49]

    > Почему в первом же посте не сказали, что ЭТО НЕВОЗМОЖНО

    да ну? я ж сказал - бессмысленно
  • stas © (04.09.08 17:37) [50]
    1. Гарантирует уникальность автоинкримент
    2. определить последнию вставленную запись универсальным методом можно
    select max(ID) from mytable в рамках одной транзакции
    и без извращений описаных в Ega23 ©   (04.09.08 13:31) [31]
    если так рассуждать можно любой метод завалить
    3. Давать глупые советы и доказывать что они умные еще глупее тем более если у тебя в анкете буква M
    4. чем глупее [5] чем [39] обоснуй пожалуйста
    5. Попробуйте доказать обратное 1 и 2.
  • Ega23 © (04.09.08 17:43) [51]

    > 1. Гарантирует уникальность автоинкримент


    1. Не гарантирует (для MSSQL способы "ломания" я уже приводил. Есть и другие).
    2. Есть далеко не везде.
    3. select max(ID) Если уж взялся такое писать, то пиши как положено:
    select IsNull(max(ID) + 1, 1)

  • Правильный$Вася (04.09.08 17:43) [52]

    > определить последнию вставленную запись универсальным методом
    > можноselect max(ID) from mytable в рамках одной транзакции

    только в однопользовательском случае, не бывает междупользовательских транзакций
    в остальных случаях последняя вставленная может быть совсем не твоя
    мало того, если инкремент делать -1, то и не max вовсе нужно использовать
  • stas © (04.09.08 17:48) [53]
    Ega23 ©   (04.09.08 17:43) [51]
    зачем +1 это же не будет ID последней вставленной записи.
  • Ega23 © (04.09.08 18:01) [54]

    > зачем +1 это же не будет ID последней вставленной записи.


    Зачем мне ID "последней вставленной записи"?
    И что будет, если таблица пустая?
  • Правильный$Вася (04.09.08 18:25) [55]

    > Зачем мне ID "последней вставленной записи"?

    Олег, ты заголовок темы забыл :)
    а зачем - так хотя бы для того, чтобы использовать его в других таблицах в рамках транзакции

    > И что будет, если таблица пустая?

    вряд ли она будет пустая, если запись только что добавили (хотя варианты есть, конечно)
  • Ega23 © (04.09.08 18:39) [56]

    > Олег, ты заголовок темы забыл :)
    > а зачем - так хотя бы для того, чтобы использовать его в
    > других таблицах в рамках транзакции


    Declare @ID int;
    Select @ID=IsNull(Max(ID) + 1, 1) from Table;
    Insert into Table (ID, ....) Values (@ID, ...)



    Только так, по-другому низя....
  • stas © (04.09.08 21:41) [57]
    Ega23 ©   (04.09.08 18:39) [56]

    я предлагал так:
    Declare @ID int;
    Insert into Table (....) Values ( ...)
    Select @ID=select Max(ID)  from Table;

  • stas © (04.09.08 21:58) [58]
    Правильный$Вася   (04.09.08 17:43) [52]

    > begin tran
    > Declare @ID int
    > Insert into Table (....) Values ( ...)
    > Select @ID=select Max(ID)  from Table;
    > commit tran

    Это пройдет в рамках одной транзакции, что исключает между инструкциями выполнение другой транзакции
  • Правильный$Вася (04.09.08 22:14) [59]

    > stas ©   (04.09.08 21:58) [58]

    дудки
    другая транзакция (от другого подключения) может запросто закончиться где-нить между Insert и select, в результате ты увидишь чужой id
  • stas © (04.09.08 22:46) [60]
    Правильный$Вася   (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, в некоторых остается. Так же как и в любом из предложеных методов.
  • Правильный$Вася (04.09.08 22:58) [61]

    > сократить вероятность можно

    можно
    но при наличии отличной от нуля вероятности такой метод можно смело сливать в унитаз
  • Petr V. Abramov © (04.09.08 23:12) [62]

    > Мне же нужен по возможности универсальный вариант, ну пусть
    > хотя бы одинаково работающий в Access, MySQL, MSSQL, Oracle.
    >  

    для перечисленных СУБД оптимального универсального варианта нет.
  • evvcom © (05.09.08 08:38) [63]
    еще один универсал? :-)
 
Конференция "Базы" » ID последней добавленной записи [D7, любая СУБД]
Есть новые Нет новых   [134477   +43][b:0.001][p:0.002]