如何从oracle合并查询返回主键

时间:2012-11-06 12:53:51

标签: oracle merge oracle10g sequence sql-returning

我想从oracle合并查询中返回主键。 我使用单个语句插入,如果不存在,我不想使用过程或函数这样做..

这是示例查询

merge into myTable e
  using (select :empname name from dual) s
  on (UPPER(TRIM(e.empname)) = UPPER(TRIM(s.name)))
  when not matched then insert (empname) 
    values (s.name)

我需要获取myTable的另一个主键字段。使用序列和触发器插入主键

我尝试添加RETURNING empID into :empId,但却出错

2 个答案:

答案 0 :(得分:10)

有一个问题。

  1. Merge Into不支持Returning Into,因此无效。
  2. 不会始终使用序列,因为它仅在插入新记录时使用。
  3. 获取序列的现有值将不起作用,因为如果要在当前会话中未使用序列时查询Sequence.currval,则会出现错误。
  4. 要解决它:

    1. 使用过程或匿名程序块尝试更新值。如果更新后sql%rowcount返回0,请改为执行插入。
    2. 使用选择(查询UPPER(TRIM(name)))查找已更新的记录。

答案 1 :(得分:3)

你可以试试这个。您需要声明一个包来捕获您的id,否则它将不会对SQL语句可见,您将收到错误:

pls-00231:功能 名称 可能未在SQL中使用

因此,首先使用要捕获的函数创建包,然后再从merge语句中访问ID:

CREATE OR REPLACE PACKAGE CaptureId
AS
   FUNCTION SaveId(newId IN NUMBER) RETURN NUMBER;
   FUNCTION GetId RETURN NUMBER;
END;

CREATE OR REPLACE PACKAGE BODY CaptureId
AS
   capturedId NUMBER(10);

   FUNCTION SaveId(newId IN NUMBER) RETURN NUMBER IS
   BEGIN
      capturedId := newId;
      RETURN capturedId;
   END;

   FUNCTION GetId RETURN NUMBER IS
   BEGIN
      RETURN capturedId;
   END;
END;

给定一个简单的表和序列生成器定义为:

CREATE TABLE EMPLOYEE
(
    EMPLOYEE_ID NUMBER(10) NOT NULL,
    FIRST_NAME VARCHAR2(120) NOT NULL,
    LAST_NAME VARCHAR2(120) NOT NULL,
    CONSTRAINT PK_EMPLOYEE PRIMARY KEY (EMPLOYEE_ID) ENABLE
);

CREATE SEQUENCE SEQ_EMPLOYEE;

然后,您可以在匿名块中使用包与merge语句来捕获id并返回它。请注意,这是一个非常简单的示例,它不适用于数组绑定变量,除非您重新编写包以将ID捕获到表类型中。如果我有机会,我可能会尝试将一个示例放在一起。

BEGIN
   MERGE INTO EMPLOYEE USING (SELECT CaptureId.SaveId(:myInputId) AS EMPLOYEE_ID,
                                     :myFirstName as FIRST_NAME,
                                     :myLastName as LAST_NAME
                                FROM DUAL) B
      ON (A.EMPLOYEE_ID = B.EMPLOYEE_ID)
   WHEN NOT MATCHED THEN
       INSERT (EMPLOYEE_ID,
               FIRST_NAME,
               LAST_NAME)
       VALUES (CaptureId.SaveId(SEQ_EMPLOYEE.NEXTVAL),
               B.FIRST_NAME,
               B.LAST_NAME)
   WHEN MATCHED THEN
     UPDATE SET A.FIRST_NAME= B.FIRST_NAME,
                A.LAST_NAME= B.LAST_NAME;

   SELECT CaptureId.GetId INTO :myOutputId FROM DUAL;
END;