2016-11-10 12 views
10

Przyjmijmy następujące wiersz myTable:Oracle SQL - można zwrócić "przed" stanu wartość kolumny

id  = 1 
letter = 'a' 

W Oracle, można łatwo wykonać następujące czynności:

update myTable set 
    letter = 'b' 
where id = 1 
returning letter 
into myVariable; 

i myVariable będzie wówczas posiadać wartość "b".

Co szukam jest jakiś sposób zwrotu „przed” wartość listu

tj. zastąpić poprzednią aktualizację z:

update myTable set 
    letter = 'b' 
where id = 1 
returning letter "before the update" 
into myVariable; 

i myVariable powinien następnie przytrzymaj wartość 'A';

Rozumiem, że T-SQL może to osiągnąć poprzez klauzulę OUTPUT.

Czy istnieje równoważny sposób Oracle, aby to osiągnąć, więc nie muszę najpierw robić "wybierz" tylko po to, aby uzyskać wcześniejszą wartość?

Odpowiedz

8
update 
    (
    select T.*, (select letter from DUAL) old_letter 
    from myTable T 
    where id=1 
) 
    set letter = 'b' 
returning old_letter into myVariable; 

Testowane na Oracle 11.2

+3

To jest intrygujące. –

+0

Rozwiązanie Brillant !. Można go nieco uprościć, po prostu wybierz T. *, T.letter AS old_letter ..... ' – krokodilko

+2

@krokodilko Przetestowałem" uproszczony "' letter as old_letter' - nie działa. Oracle w tym przypadku zwraca nową wartość. Tylko podselekcja oszukuje Oracle – Mike

1

Uważam, że nie można tego zrobić za pomocą prostego SQL (a ja się mylę, widząc Mikes' odpowiedź :-))

Jednym ze sposobów może być przy użyciu innej kolumny i spust; na przykład, że masz tabelę z kolumną a, można dodać kolejną kolumnę old_a przechowywać starą wartość a i wypełnić go z wyzwalaczem:

create table testUpdate(a number, old_a number); 
create or replace trigger trgUpdate 
before update on testUpdate 
for each row 
begin 
    if :new.a != :old.a then /* assuming not null values for simplicity */ 
     :new.old_a := :old.a; 
    end if; 
end; 
insert into testUpdate values (1, null); 

Po uruchomieniu aktualizacji stara wartość jest przechowywane w th old_a kolumny i zwrócony przez klauzuli returning

SQL> declare 
    2  vA number; 
    3 begin 
    4  update testUpdate 
    5  set a = 9 
    6  returning old_a 
    7  into vA; 
    8  -- 
    9  dbms_output.put_line(vA); 
10 end; 
11/
1 

Biorąc jednak pod uwagę, że to musi dodać kolumnę i spust do stolika, uważam to rozwiązanie bardziej ćwiczeniem niż coś, chciałbym mieć w produkcja DB

+0

dzięki bardzo @Aleksej - jak na mój komentarz do Mike Wybrałbym opcję select, a następnie aktualizację dotyczącą tego podejścia. Jednak twoja odpowiedź, jak przypuszczam, uwydatnia to, co uważam za dziwne: wyzwalacze Oracle mają dostęp do: starych i nowych wartości, ale z odpowiedzi, które widzę tutaj, Oracle nie ujawnia tych samych funkcji za pomocą SQL. Jest tak wiele przypadków użycia, nie mogłem nawet zacząć wymieniać ich wszystkich. – Pancho

1

Jeśli nie ma wiele aktualizacje można zrobić aktualizację w pętli i zestarzeć wartości:

declare 
CURSOR c IS SELECT letter, id FROM myTable 
    FOR UPDATE OF letter; 
begin 
    open c; 
    for x in c loop 
    -- old value is in x.letter. You can assign it here 
    update myTable set letter = 'b' where id = x.id;  
    end loop; 
    commit; 
    close c; 
end; 
/
+0

bardzo dziękuję @Kacper - myślę, że wolałbym użyć opcji select, a następnie aktualizacji w stosunku do tego podejścia – Pancho

+0

@Pancho Tak, myślę, że wybór jest lepszy. – Kacper