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;
A последовательность будет делать работу, посмотрите, например,последовательности Oracle