В Oracle, как сохранить sequence.nextval в переменной для повторного использования в нескольких вставках?

13

Я пишу скрипт для заполнения некоторых таблиц данными для тестирования.

Я хотел бы написать что-то вроде следующего, но я не знаю, как это сделать (я Oracle 11g)

SET ENABLED_USER_ID = SEQ.NEXTVAL; // PSEUDOCODE
SET DISABLED_USER_ID = SEQ.NEXTVAL; // PSEUDOCODE

INSERT INTO USERS
        (ID,      USR_NAME)
VALUES  (:ENABLED_USER_ID, 'ANDREW');
INSERT INTO CAR
       (CAR_ID,         CAR_NAME, USR_ID)
VALUES (CARSEQ.NEXTVAL, 'FORD',   :ENABLED_USER_ID);

INSERT INTO USERS
        (ID,      USR_NAME)
VALUES  (:DISABLED_USER_ID, 'ANDREW');
INSERT INTO CAR
       (CAR_ID,         CAR_NAME, USR_ID)
VALUES (CARSEQ.NEXTVAL, 'FORD',   :DISABLED_USER_ID);

Я знаю, что мог бы изменить порядок запросов и использовать sequence.currvalссылку, но я бы предпочел, чтобы идентификатор сохранялся в правильно названных переменных.

Может быть, я должен просто обернуть сценарий в, DECLARE ... BEGIN ... END;но я надеюсь, что есть более краткий способ сделать это.


Дополнение 27 мая 2011 15:31

Кажется, что в любом случае я должен объявить переменные в DECLAREблоке. Так что я пытаюсь с

DECLARE
  USER_ID NUMBER(10,0) := 1;
BEGIN   
  insert into TEST_USER
  values (user_id, 'andrew', sysdate);   
END;

но я получаю следующую ошибку

Caused by: java.sql.SQLException: ORA-06550: **line 2, column 27:**
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:

  * & = - + ; < / > at in is mod remainder not rem
  <an exponent (**)> <> or != or ~= >= <= <> and or like like2
  like4 likec between || multiset member submultiset

Это указывает на объявление переменной.

Я использую Java для загрузки сценария из файла и запускаю его с помощью драйвера JDBC Oracle (ojdbc14-10.2.0.4.0.jar) на сервере Oracle 11g.

Таблица TEST_USER была создана с

create table TEST_USERS (
    id number(10, 0) not null,
    name varchar2(100),
    date_ins date default sysdate,
    primary key (id)
);
basilikode
источник

Ответы:

11

Я думаю, что это идет так

DECLARE
    ENABLED_USER_ID PLS_INTEGER;
    DISABLED_USER_ID PLS_INTEGER;
BEGIN
    ENABLED_USER_ID := SEQ.NEXTVAL;
    DISABLED_USER_ID := SEQ.NEXTVAL;

    INSERT INTO USERS (ID, USR_NAME)
    VALUES  (ENABLED_USER_ID, 'ANDREW');

    INSERT INTO CAR (CAR_ID, CAR_NAME, USR_ID)
    VALUES (CARSEQ.NEXTVAL, 'FORD', ENABLED_USER_ID);

    INSERT INTO USERS (ID, USR_NAME)
    VALUES  (DISABLED_USER_ID, 'ANDREW');

    INSERT INTO CAR (CAR_ID, CAR_NAME, USR_ID)
    VALUES (CARSEQ.NEXTVAL, 'FORD', DISABLED_USER_ID);
END;
/
bernd_k
источник
10

Это можно сделать с помощью предложения RETURNING в первом INSERTутверждении.

ОБНОВЛЕНИЕ: случайно написал об этом в моем блоге в последнее время.

Gaius
источник
8

Вам понадобится блок, если вы объявляете переменные

В версии 11g улучшена поддержка последовательностей, поэтому вы можете использовать их следующим образом:

ENABLED_USER_ID := SEQ.NEXTVAL;

вместо того, чтобы использовать selectутверждение (хотя оба будут работать)

Другие варианты сохранения значений включают сохранение их в таблицу или создание контекста , но я думаю, что sequence.currvalздесь действительно «правильный ответ»

Джек говорит, попробуйте topanswers.xyz
источник
7
SELECT seq.nextval 
   INTO ENABLED_USER_ID
FROM dual;
a_horse_with_no_name
источник
ENABLED_USER_ID должен идти в блоке объявления, верно?
Василикод
@Xan: да, переменные могут быть определены только в разделе DECLARE, который, в свою очередь, действителен только при наличии блока PL / SQL
a_horse_with_no_name
4

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

INSERT INTO USERS
    (ID,      USR_NAME)
VALUES  (SEQ.NEXTVAL, 'ANDREW');
INSERT INTO CAR
   (CAR_ID,         CAR_NAME, USR_ID)
VALUES (CARSEQ.NEXTVAL, 'FORD',   SEQ.CURRVAL);
mustaccio
источник