Oracle SQL: как читать и увеличивать поле - PullRequest
8 голосов
/ 08 января 2010

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

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

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

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

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

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

Ответы [ 4 ]

9 голосов
/ 08 января 2010

В данном конкретном случае последовательность является правильным решением, как уже упоминалось. Но если в будущем вам потребуется что-то обновить и вернуть значение в одном выражении, вы можете использовать предложение 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 .

4 голосов
/ 08 января 2010

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

Создайте последовательность один раз, используя любое значение START WITH:

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;
2 голосов
/ 08 января 2010

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

"SELECT ДЛЯ ОБНОВЛЕНИЯ;

0 голосов
/ 08 января 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...