Operacja UPSERT aktualizuje lub wstawia wiersz do tabeli, w zależności od tego, czy tabela ma już wiersz zgodny z danymi:
if table t has a row exists that has key X:
update t set mystuff... where mykey=X
else
insert into t mystuff...
Ponieważ Oracle nie ma określonej instrukcji UPSERT, jaki jest najlepszy sposób na to?
Instrukcja MERGE scala dane między dwiema tabelami. Użycie DUAL pozwala nam użyć tego polecenia. Pamiętaj, że nie jest to chronione przed równoczesnym dostępem.
źródło
Podwójny przykład powyżej, który jest w PL / SQL, był świetny, ponieważ chciałem zrobić coś podobnego, ale chciałem, aby to było po stronie klienta ... więc tutaj jest SQL, który wysłałem podobną instrukcję bezpośrednio z jakiegoś C #
Jednak z perspektywy C # zapewnia to wolniejsze działanie niż przeprowadzanie aktualizacji i sprawdzanie, czy zmienione wiersze miały wartość 0, i wykonywanie wstawiania, jeśli tak było.
źródło
MERGE
i wolę używać znacznie prostszegoDELETE
niżINSERT
.MERGE INTO mytable d USING (SELECT 1 id, 'x' name from dual) s ON (d.id = s.id) WHEN MATCHED THEN UPDATE SET d.name = s.name WHEN NOT MATCHED THEN INSERT (id, name) VALUES (s.id, s.name);
Inna alternatywa bez kontroli wyjątku:
źródło
źródło
Żadna z dotychczas udzielonych odpowiedzi nie jest bezpieczna w obliczu równoczesnego dostępu , jak wskazano w komentarzu Tima Sylvester'a, i nie podniesie wyjątków w przypadku wyścigów. Aby to naprawić, zestaw wstawiania / aktualizacji musi być zawinięty w jakąś instrukcję pętli, aby w przypadku wyjątku ponowna próba została wykonana.
Oto przykład, w jaki sposób kod Grommita można owinąć w pętlę, aby był bezpieczny, gdy jest uruchamiany jednocześnie:
Uwaga: W trybie transakcji
SERIALIZABLE
, którego nie polecam btw, możesz wpaść na ORA-08177: zamiast tego nie możesz serializować dostępu dla wyjątków transakcji .źródło
Chciałbym uzyskać odpowiedź Grommita, z wyjątkiem tego, że wymaga wartości duplikowania. Znalazłem rozwiązanie, w którym może się pojawić raz: http://forums.devshed.com/showpost.php?p=1182653&postcount=2
źródło
INSERT (B.CILT, B.SAYFA, B.KUTUK, B.MERNIS_NO) VALUES (E.CILT, E.SAYFA, E.KUTUK, E.MERNIS_NO);
?Uwaga dotycząca dwóch sugerowanych rozwiązań:
1) Wstaw, jeśli wyjątek, a następnie zaktualizuj,
lub
2) Zaktualizuj, jeśli sql% rowcount = 0, następnie wstaw
Pytanie, czy najpierw wstawić, czy zaktualizować, zależy również od aplikacji. Oczekujesz więcej wstawek lub aktualizacji? Ten, który najprawdopodobniej odniesie sukces, powinien zająć pierwsze miejsce.
Jeśli wybierzesz niewłaściwy, otrzymasz niepotrzebne odczyty indeksu. Nie jest to wielka sprawa, ale wciąż coś do rozważenia.
źródło
Pierwszej próbki kodu używam od lat. Zauważ, że nie znaleziono, a nie policz.
Poniższy kod jest prawdopodobnie nowym i ulepszonym kodem
W pierwszym przykładzie aktualizacja wykonuje wyszukiwanie indeksu. Musi to zrobić, aby zaktualizować prawy wiersz. Oracle otwiera niejawny kursor i używamy go do zawijania odpowiedniej wstawki, abyśmy wiedzieli, że wstawka nastąpi tylko wtedy, gdy klucz nie istnieje. Ale wstawka jest niezależnym poleceniem i musi wykonać drugie wyszukiwanie. Nie znam wewnętrznego działania polecenia scalania, ale ponieważ polecenie to pojedyncza jednostka, Oracle może wykonać poprawne wstawienie lub aktualizację za pomocą pojedynczego wyszukiwania indeksu.
Myślę, że scalanie jest lepsze, gdy trzeba wykonać pewne przetwarzanie, co oznacza pobieranie danych z niektórych tabel i aktualizowanie tabeli, ewentualnie wstawianie lub usuwanie wierszy. Ale w przypadku pojedynczego wiersza można rozważyć pierwszy przypadek, ponieważ składnia jest częstsza.
źródło
Skopiuj i wklej przykład wstawiania jednej tabeli do drugiej za pomocą MERGE:
Wynik:
źródło
Spróbuj tego,
źródło
Od http://www.praetoriate.com/oracle_tips_upserts.htm :
„W Oracle9i UPSERT może wykonać to zadanie za pomocą jednego polecenia:”
źródło