Oracle SQL -我可以返回列值的“before”状态吗

juzqafwq  于 2023-08-03  发布在  Oracle
关注(0)|答案(4)|浏览(99)

假设myTable中有以下行:

id     =  1
letter = 'a'

字符串
在Oracle中,您可以轻松地执行以下操作:

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


而myVariable将保存值'b'。
我正在寻找的是返回字母“之前”值的某种方法
即,将以前的更新替换为:

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

和myVariable应该保存值'a';

我知道T-SQL可以通过OUTPUT子句实现这一点。
有没有一种与Oracle等效的方法来实现这一点,这样我就不必首先执行“select”操作来获取before值?

uqdfh47h

uqdfh47h1#

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

字符串
在Oracle 11.2上测试

7kqas0il

7kqas0il2#

如果没有太多的更新,你可以在循环中更新并获取旧值:

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;
/

字符串

jdg4fx2g

jdg4fx2g3#

我相信你不能用一个简单的SQL语句来完成它(我错了,看到Mikes的答案:-))
一种方法是使用另一列和一个触发器;例如,假设你有一个列为a的表,你可以添加另一个列old_a来存储a的旧值,并使用触发器填充它:

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);

字符串
运行更新时,旧值存储在old_a列中,并由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


但是,考虑到这需要向表中添加一个列和一个触发器,我认为这个解决方案更像是一个练习,而不是我希望在生产数据库中使用的东西

pdtvr36n

pdtvr36n4#

沿着其他超级酷的特性,如本地布尔支持,我很高兴看到Oracle 23 c引入了一种简洁的方式来实现我的上述要求,所以我想我应该分享一下!
下面是Oracle Database & Cloud Technology Blog的相关摘录:

UPDATE和MERGE语句的RETURNING子句

此子句在很久以前就已作为EXECUTE IMMEDIATE语句的一部分实现。但是,在Oracle Database 23 c中,我们可以发现它是传统静态DML语句的一部分-在这种情况下,它允许从由该语句处理的行中获取列的旧值和新值:
SQL> SELECT名称,sal FROM雇员WHERE名称= 'KING';
名称SAL
国王5000型
SQL>变量旧薪金NUMBER SQL>变量新薪金NUMBER
返回旧的工资,新的工资到:旧的工资,:新的工资;已更新1行。

SQL>打印旧薪金旧薪金

5000

字符串

SQL>打印新薪金新薪金

6000

相关问题