Получение вставленной записи в Oracle db - PullRequest
2 голосов
/ 25 августа 2009

Я использую Oracle на сервере базы данных, от клиента XP, используя VB6 и ADO. В одной транзакции я вставляю одну запись в родительскую таблицу, которая имеет триггер и последовательность для создания уникального идентификатора записи, затем этот идентификатор записи используется для связи с дочерней таблицей для переменного числа вставок в дочернюю таблицу. Для производительности это отправляется в одной команде выполнения из моего клиентского приложения. Например (упрощенный пример):

объявляет Recordid int;
начать
вставить в ParentTable ( список полей ) Значения ( список данных );
Выберите ParentTableSequence.currVal в Recordid из двойного;
вставить в ChildTable (RecordID, список полей ) значения (Recordid, список данных );
вставить в ChildTable (RecordID, список полей ) значения (Recordid, список данных );
... множественное, переменное число дополнительных вставок ChildTable
совершить;
конец;

Это работает нормально. Мой вопрос: мне также нужно вернуть клиенту Recordid, который был создан для вставок. На SQL Server я могу добавить что-то вроде select в Scope_Identity () после фиксации, чтобы вернуть клиенту набор записей с уникальным идентификатором.

Но как я могу сделать что-то подобное для Oracle (это не обязательно набор записей, мне просто нужно это длинное целое значение)? Я попробовал несколько вещей, основанных на результатах поиска в сети, но не смог найти решение.

Спасибо!
Markl

1 Ответ

6 голосов
/ 25 августа 2009

Эти две строки могут быть сжаты в один оператор:

--  insert into ParentTable (field list) Values (data list);
--  Select ParentTableSequence.currVal into Recordid from dual;
insert into ParentTable (field list) Values (data list)
  returning ParentTable.ID into Recordid;

Если вы хотите передать идентификатор обратно вызывающей программе, вам необходимо определить свою программу как хранимую процедуру или функцию, возвращая Recordid в качестве параметра OUT или значения RETURN соответственно.

Редактировать

MarkL прокомментировал:

Это больше Oracle PL / SQL вопрос чем что-либо еще, я верить.

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

SQL> create or replace type new_emp_t as object
  2      (ename varchar2(10)
  3       , sal number (7,2)
  4       , job varchar2(10));
  5  /

Type created.

SQL>
SQL> create or replace type new_emp_nt as table of new_emp_t;
  2  /

Type created.

SQL>
SQL> create or replace procedure pop_new_dept
  2      (p_dname in dept.dname%type
  3       , p_loc in dept.loc%type
  4       , p_mgr in emp.empno%type
  5       , p_staff in new_emp_nt
  6       , p_deptno out dept.deptno%type)
  7  is
  8      l_deptno  dept.deptno%type;
  9  begin
 10      insert into dept
 11          (dname, loc)
 12      values
 13          (p_dname, p_loc)
 14      returning deptno into l_deptno;
 15      update emp
 16          set deptno = l_deptno
 17              , job = 'MANAGER'
 18              , mgr = 7839
 19          where empno = p_mgr;
 20      forall i in p_staff.first()..p_staff.last()
 21          insert into emp
 22              (ename
 23                  , sal
 24                  , job
 25                  , hiredate
 26                  , mgr
 27                  , deptno)
 28          values
 29              (p_staff(i).ename
 30                , p_staff(i).sal
 31                , p_staff(i).job
 32                , sysdate
 33                , p_mgr
 34                , l_deptno);
 35      p_deptno := l_deptno;
 36  end pop_new_dept;
 37  /

Procedure created.

SQL>
SQL> set serveroutput on
SQL>
SQL> declare
  2      dept_staff new_emp_nt;
  3      new_dept dept.deptno%type;
  4  begin
  5      dept_staff := new_emp_nt(new_emp_t('MARKL', 4200, 'DEVELOPER')
  6                               , new_emp_t('APC', 2300, 'DEVELOPER'));
  7      pop_new_dept('IT', 'BRNO', 7844, dept_staff, new_dept);
  8      dbms_output.put_line('New DEPTNO = '||new_dept);
  9  end;
 10  /
New DEPTNO = 70

PL/SQL procedure successfully completed.

SQL>

Первичные ключи для DEPT и EMP назначаются через триггеры. Синтаксис FORALL является очень эффективным способом вставки записей (он также работает для UPDATE и DELETE). Это может быть записано как FUNCTION для возврата нового DEPTNO вместо этого, но обычно считается лучшей практикой использовать PROCEDURE при вставке, обновлении или удалении.

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

Редактировать 2

Что касается производительности, массовые операции с использованием FORALL определенно будут выполняться лучше, чем несколько отдельных вставок. В SQL операции set всегда предпочтительнее, чем запись за записью. Однако, если мы имеем дело только с несколькими записями каждый раз, может быть трудно заметить разницу.

Создание коллекции PL / SQL (которую вы считаете временной таблицей в SQL Server) может быть дорогостоящим с точки зрения памяти. Это особенно верно, если код выполняется многими пользователями, потому что это происходит из-за выделения памяти на уровне сеанса, а не из общей глобальной области. Когда мы имеем дело с большим количеством записей, лучше заполнить массив кусками, возможно, используя синтаксис BULK COLLECT с предложением LIMIT.

Онлайн-документация Oracle довольно хороша. В Руководстве разработчика PL / SQL есть целая глава о коллекциях. Узнайте больше .

...