8

我想从 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 ,但它给出了错误

4

2 回答 2

10

有问题。

  1. Merge Into不支持Returning Into,所以不行。
  2. 该序列并不总是被使用,因为它只在插入新记录时使用。
  3. 获取序列的现有值将不起作用,因为如果要在当前会话中尚未使用序列时查询 Sequence.currval,则会出现错误。

要解决它:

  1. 使用过程或匿名程序块来尝试更新值。如果sql%rowcount更新后返回 0,则改为执行插入。
  2. 使用选择(查询UPPER(TRIM(name)))来查找已更新的记录。
于 2012-11-06T13:11:09.513 回答
3

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

pls-00231: 函数 不能在 SQL 中使用

因此,首先创建包含要捕获的函数的包,然后从合并语句中访问 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;

然后,您可以使用带有合并语句的匿名块中的包来捕获 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;
于 2017-06-12T21:59:35.450 回答