2011-01-04 14 views
1

Ich habe eine einfache INSERT-Abfrage, wo ich stattdessen UPDATE verwenden muss, wenn der Primärschlüssel ein Duplikat ist. In MySQL scheint dies einfacher, in Oracle scheint es, dass ich MERGE verwenden muss.UPDATE auf INSERT doppelte Primärschlüssel in Oracle?

Alle Beispiele, die ich von MERGE finden konnte, hatten eine Art "Quelle" und "Ziel" -Tabellen, in meinem Fall sind Quelle und Ziel die gleiche Tabelle. Ich konnte die Beispiele nicht nachvollziehen, um eine eigene Abfrage zu erstellen.

Ist MERGE der einzige Weg oder gibt es vielleicht eine bessere Lösung?

INSERT INTO movie_ratings 
VALUES (1, 3, 5) 

Es ist im Grunde dieser und der Primärschlüssel ist die ersten zwei Werte, so ein Update so sein würde:

UPDATE movie_ratings 
SET rating = 8 
WHERE mid = 1 AND aid = 3 

Ich dachte, einen Auslöser zu verwenden, die automatisch die Update-Anweisung ausführen würde, wenn die INSERT wurde nur dann aufgerufen, wenn der Primärschlüssel ein Duplikat ist. Gibt es ein Problem damit? Ich brauche etwas Hilfe mit Auslösern, da ich Schwierigkeiten habe, sie zu verstehen und meine eigenen zu machen.

+0

In einem solchen Beispiel wäre es sinnvoll, die (optionale) Liste der Spaltennamen im INSERT zu verwenden, um uns genügend von der Tabellenstruktur zu geben. Vielleicht, wenn Sie zeigen, was in MySQL getan wird, sehen die Leute vielleicht, wonach Sie suchen - oder vielleicht ist das meine Neugierde/Faulheit. –

+0

Die Tabellenstruktur ist impliziert, es ist Mitte (Int), Hilfe (Int), Bewertung (Int). –

Antwort

10

MERGE ist die Anweisung 'INSERT oder UPDATE als geeignet' in Standard SQL und wahrscheinlich auch in Oracle SQL.

Ja, benötigen Sie einen 'Tisch' aus zu verschmelzen, aber man kann fast sicher, dass die Tabelle on the fly erstellen:

MERGE INTO Movie_Ratings M 
     USING (SELECT 1 AS mid, 3 AS aid, 8 AS rating FROM dual) N 
      ON (M.mid = N.mid AND M.aid = N.aid) 
     WHEN  MATCHED THEN UPDATE SET M.rating = N.rating 
     WHEN NOT MATCHED THEN INSERT( mid, aid, rating) 
          VALUES(N.mid, N.aid, N.rating); 

(. Syntax nicht überprüft)

+0

Das hat den Trick gemacht. Immer lernen tolle neue Sachen :) –

+0

@ Jonathan-leffler Ich habe die Antwort bearbeitet, um die 'AS' aus 'USING ... AS N' zu entfernen, da es einen Fehler für mich auf Oracle 11.1 verursacht – Stompchicken

+0

Oracle erlaubt ** Multi-Tabelle * * fügt/aktualisiert mit INSERT/UPDATE-Anweisung, aber nicht mit der MERGE-Anweisung. Über unfertige Software sprechen ... –

1

Ein typischer Weg, dies zu tun, ist

  • die INSERT Durchführung und einen DUP_VAL_ON_INDEX zu fangen, und führt dann eine UPDATE statt
  • die UPDATE ersten Durchführung und wenn SQL% rows = 0 eine INSERT ausführen

Sie können keinen Trigger für eine Tabelle schreiben, die eine andere Operation für dieselbe Tabelle ausführt. Das verursacht einen Oracle-Fehler (Tabellen mutieren).

+0

Wusste das nicht, danke für die Klarstellung. Aber das sollte ein Kommentar sein, da er nicht unbedingt meine Frage beantwortet. –

+0

@Nazgulled: hinzugefügt einige Gedanken über die MERGE (ich denke, es gilt als eine Antwort jetzt) ​​ – sjngm

+0

@Nazgulled: Ich habe meine MERGE-Zeug entfernt, da Jonathan Leffler Vorschlag könnte tatsächlich so funktionieren. Ich hatte eine andere Lösung im Sinn. – sjngm

0

Ich bin ein T -SQL Typ aber ein Auslöser ist in diesem Fall keine gute Lösung. Die meisten Trigger sind keine guten Lösungen. In T-SQL, würde ich einfach ausführen eine IF EXISTS (SELECT * FROM dbo.Table WHERE ...), aber in Oracle, müssen Sie die Zählung wählen ...

DECLARE 
    cnt NUMBER; 
BEGIN 
    SELECT COUNT(*) 
    INTO cnt 
    FROM mytable 
    WHERE id = 12345; 

    IF(cnt = 0) 
    THEN 
    ... 
    ELSE 
    ... 
    END IF; 
END; 

Es scheint, dass einfädelt was Sie in diesem Fall brauchen:

MERGE INTO movie_ratings mr 
USING (
    SELECT rating, mid, aid 
    WHERE mid = 1 AND aid = 3) mri 
ON (mr.movie_ratings_id = mri.movie_ratings_id) 

WHEN MATCHED THEN 
    UPDATE SET mr.rating = 8 WHERE mr.mid = 1 AND mr.aid = 3 

WHEN NOT MATCHED THEN 
    INSERT (mr.rating, mr.mid, mr.aid) 
    VALUES (1, 3, 8) 

Wie ich schon sagte, ich bin ein T-SQL-Typ, aber die Grundidee ist hier zu „verbinden“, um die movie_rating Tisch vor sich. Wenn bei der Verwendung des Beispiels "Wenn vorhanden" keine Leistung auftritt, würde ich es zur besseren Lesbarkeit verwenden.

Verwandte Themen