2012-11-06 10 views
6

Ich möchte den Primärschlüssel aus einer Oracle Merge-Abfrage zurückgeben. Ich bin eine einzige Anweisung zu verwenden, wenn nicht einfügen existieren und ich will nicht, Prozedur oder Funktion verwenden, dies zu tun ..Zurückgeben des Primärschlüssels aus der Oracle Merge-Abfrage

dies ist die Beispielabfrage

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) 

und ich brauche zu bekommen ein weiteres Primärschlüsselfeld der myTable. der Primärschlüssel mit Sequenz eingefügt und auslösen

Ich versuchte RETURNING empID into :empId Zugabe, aber es gibt Fehler

+0

Es „gibt einen Fehler“, weil [es keine Möglichkeit, in verwenden Rückkehr] (http://docs.oracle.com/cd/E11882_01/server.112/e26088/statements_9016.htm#SQLRF01606) . Wenn Sie jedoch das PK _by definition_ zurückgeben möchten, müssen Sie es in etwas zurückgeben, was bedeutet, dass Sie einen Wrapper mit einer Beschreibung verwenden. Was ist falsch daran, dass dieser Wrapper ein PL/SQL-Block ist?Wenn Sie nicht wollen, dass es eine Prozedur/Funktion ist, müssen Sie angeben, was Sie verwenden möchten, andernfalls ist es unmöglich, diese Frage gut zu beantworten. – Ben

+1

Ich verwende eine einzelne Oracle-Abfrage, um dies zu tun. Die: empId übergebe ich diese Abfrage als Ausgabeparameter. Ist es möglich, den Ausgabeparameterwert von einer einzelnen Zusammenführungsabfrage zu erhalten? –

+1

Vielleicht möchten Sie dies lesen - http://www.oracle-developer.net/display.php?id=413 –

Antwort

8

Es gibt ein Problem.

  1. Merge Into nicht unterstützt Returning Into, das wird so nicht funktionieren.
  2. Die Sequenz wird nicht immer verwendet, da sie nur beim Einfügen neuer Datensätze verwendet wird.
  3. Das Abrufen des vorhandenen Werts einer Sequenz funktioniert nicht, da Sie einen Fehler erhalten, wenn Sie Sequence.currval abfragen möchten, obwohl die Sequenz noch nicht in der aktuellen Sitzung verwendet wurde.

es zu lösen:

  1. ein Verfahren oder ein anonymen Programmblock verwenden, um zu versuchen, den Wert zu aktualisieren. Wenn sql%rowcount nach der Aktualisierung 0 zurückgibt, führen Sie stattdessen die Einfügung durch.
  2. Verwenden Sie die Auswahl (Abfrage für UPPER(TRIM(name))), um den Datensatz zu finden, der aktualisiert wurde.
+2

Haben Sie es zur Arbeit bekommen? – GolezTrol

3

Sie können dies versuchen. Sie müssen ein Paket erklären, um Ihre ID zu erfassen, sonst ist es nicht auf die SQL-Anweisung zu sehen sein wird und Sie erhalten eine Fehlermeldung erhalten:

pls-00231: functionNamekann nicht in SQL verwendet werden

Also, zuerst das Paket mit Funktionen erstellen zu erfassen und dann später auf die ID aus der Merge-Anweisung: wie definiert

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; 

eine einfache Tabelle und Sequenzgenerator Gegeben:

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; 

Sie können das Paket dann in einem anonymen Block mit Ihrer Merge-Anweisung verwenden, um die ID zu erfassen und zurückzugeben. Beachten Sie, dass dies ein sehr einfaches Beispiel ist und nicht mit arraygebundenen Variablen funktioniert, es sei denn, Sie bearbeiten das Paket neu, um die IDs in einem Tabellentyp zu erfassen. Wenn ich eine Chance bekomme, kann ich versuchen, ein Beispiel zusammenzustellen, das dies zeigt.

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

Es gibt ein anderes Problem mit diesem Ansatz. Wenn Sie ein anderes Qualifikationsmerkmal als die EMPLOYEE_ID in der ON-Anweisung verwenden (z. B. "A.EMPLOYEE_ID = B.EMPLOYEE_ID ODER A.LAST_NAME = B.LAST_NAME"), können Sie die ID nicht erfassen. Mit diesem Qualifikationsmerkmal können Sie eine "NULL" für die "EMPLOYEE_ID" übergeben und auf einer "LAST_NAME" abgleichen. Wenn es nicht von 'EMPLOYEE_ID' gefunden wird, wird es nicht möglich sein, die' EMPLOYEE_ID' zu erfassen, die mit 'LAST_NAME' übereinstimmt. –