【问题标题】:Obtaining an inserted recordid on Oracle db在 Oracle db 上获取插入的 recordid
【发布时间】:2009-08-24 21:01:38
【问题描述】:

我在数据库服务器上使用 Oracle,来自 XP 客户端,使用 VB6 和 ADO。在一个事务中,我将一条记录插入到父表中,该表有一个触发器和序列来创建一个唯一的 recordid,然后该 recordid 用于与子表的关系,以便对子表进行可变数量的插入。为了提高性能,这是通过我的客户端应用程序的一个执行命令发送的。例如(简化示例):

declare Recordid int;  
begin  
insert into ParentTable (_field list_) Values (_data list_);  
Select ParentTableSequence.currVal into Recordid from dual;  
insert into ChildTable (RecordID, _field list_) Values (Recordid, _data list_);  
insert into ChildTable (RecordID, _field list_) Values (Recordid, _data list_);  
... multiple, variable number of additional ChildTable inserts  
commit;  
end;  

这工作正常。我的问题是:我还需要将为插入创建的 Recordid 返回给客户端。在 SQL Server 上,我可以在提交后向 Scope_Identity() 添加类似选择的内容,以将记录集返回给具有唯一 ID 的客户端。

但是我怎样才能为 Oracle 做类似的事情(不必是记录集,我只需要那个长整数值)?我根据搜索“网络”的结果尝试了很多方法,但都没有找到解决方案。

【问题讨论】:

  • 在你的 sql 结尾处简单地说:“SELECT RecordID”怎么样?

标签: oracle vb6 ado


【解决方案1】:

这两行可以压缩成一条语句:

--  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;

如果要将 ID 传递回调用程序,则需要将程序定义为存储过程或函数,分别将 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 语法是一种非常有效的插入记录的方法(它也适用于UPDATEDELETE)。这可以写成FUNCTION 来代替返回新的DEPTNO,但通常认为在插入、更新或删除时使用PROCEDURE 是更好的做法。

这将是我的首选方法,但我承认这并不符合每个人的口味。

编辑 2

就性能而言,使用FORALL 的批量操作肯定会比少数单独的插入执行得更好。在 SQL 中,集合操作总是比逐个记录更可取。但是,如果我们每次只处理少量记录,就很难注意到差异。

构建 PL/SQL 集合(您认为是 SQL Server 中的临时表)在内存方面可能会很昂贵。如果有许多用户运行代码,则尤其如此,因为它来自会话级别的内存分配,而不是共享全局区域。当我们处理大量记录时,最好以块的形式填充数组,也许使用带有LIMIT 子句的BULK COLLECT 语法。

Oracle 在线文档集相当不错。 PL/SQL Developer's Guide 有一整章是关于集合的。 Find out more

【讨论】:

  • 我喜欢将两个语句合二为一,谢谢!从逻辑上讲,我认为它会更有效吗?将其实现为存储的过程或函数不是一个可用的选项,据我所知,因为我的子表中有可变数量的插入。我没有其他选择吗?
  • 总是有选择的。如果我对您的情况有更多了解的话。您是否正在动态生成该匿名块?你是如何运行它的?
  • 是的,这个 DML 序列是动态创建的,一系列插入连接成一个字符串。使用 VB6 和 ADO。我已经尝试了多种方法来运行它(recordset.open、connection.execute 等)——大多数情况下,我不知道在 DML 中有什么才能取回记录 ID。在我的 SQL Server 配置中(诚然,苹果 vs 橙子),我在插入后有一个 Select Scope_Identity() 以将记录集返回给客户端。我相信,这更像是一个 Oracle PL/SQL 问题。
  • 绝对酷!虽然我不确定我可以用它来解决我当前的问题,但我会保存它以备将来使用。关于性能的问题:在多用户、大容量环境中,通常性能会更好,填充一个临时表并使用 forall 对其进行交互以执行插入(我认为您上面的代码,预编译),或者直接插入内联(我的初始代码,每次动态创建和编译)?还是可以在没有特定负载/性能测试的情况下可靠地说明这一点?谢谢!
猜你喜欢
  • 2011-03-09
  • 2020-08-06
  • 2013-12-21
  • 2019-12-10
  • 2011-05-26
  • 1970-01-01
  • 2011-03-16
  • 2011-12-21
  • 1970-01-01
相关资源
最近更新 更多