Oracle SQL: как читать и увеличивать поле

Я рефакторинг процедуры импорта данных для корпоративного приложения и наткнулся на фрагмент, который я хотел бы найти лучшее решение. При импорте данных мы должны создать уникальный объект для каждого набора данных, и в поле есть счетчик, который будет использоваться для последовательного присвоения этого идентификатора. Вы читаете поле, чтобы получить следующий бесплатный идентификатор и увеличить его после этого, чтобы подготовиться к следующему разу.

на данный момент это делается в два этапа в исходном приложении, написанном в 'C':

   SELECT idnext FROM mytable;
   UPDATE mytable SET idnext = idnext + 1;

очевидно, что здесь есть условие гонки, если несколько процессов делают то же самое.

Edit: важный corequisite: я не могу коснуться определения базы данных/поля, это исключает последовательность.

мы переписываем в perl, и я хотел бы сделать то же самое, но лучше. Атомное решение было бы неплохо. К сожалению, мои навыки SQL ограничены, поэтому я обращаюсь к коллективной мудрости: -)

4 ответов


в этом конкретном случае последовательность является правильным решением, как упоминалось. Но если в какой-то будущей ситуации вам нужно что-то обновить и вернуть значение в том же операторе, вы можете использовать RETURNING статья:

UPDATE atable SET foo = do_something_with(foo) RETURNING foo INTO ?

если вызывающий код PL/SQL, замените ? с локальной переменной PL/SQL; в противном случае вы можете привязать ее как выходной параметр в своей программе.

Edit: поскольку вы упомянули Perl, что-то вроде этого должно работать (непроверено):

my $sth = $dbh->prepare('UPDATE mytable SET idnext = idnext + 1 returning idnext into ?');
my $idnext;
$sth->bind_param_inout(1, $idnext, 8);
$sth->execute; # now $idnext should contain the value

посмотреть DBI.


почему бы не использовать последовательность?

создайте последовательность один раз, используя любое начало со значением, которое вы хотите:

CREATE SEQUENCE mysequence
  START WITH 1
  MAXVALUE 999999999999999999999999999
  MINVALUE 1
  NOCYCLE
  NOCACHE
  NOORDER;

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

SELECT mysequence.NEXTVAL
  INTO idnext
  FROM DUAL;

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

   UPDATE mytable 
      SET idnext = idnext + 1 
RETURNING idnext 
     INTO mylocalvariable;

используйте инструкцию SELECT FOR UPDATE. Он гарантирует взаимоисключающие права на запись:

"выберите ДЛЯ ОБНОВЛЕНИЯ;


A последовательность будет делать работу, посмотрите, например,последовательности Oracle