我有一张表格,代表校园内的位置。我在网络程序中为用户显示这些位置,我想让他们能够更改位置显示的顺序。我有一个列,称为ord
。我现在正在尝试为用户创建一种更新该列的方法,并确保这一点
1)没有ord
个重复项
2)所有ord
值都是> = 0&& < rowcount(表格)。
我想我应该用触发器来做这件事。首先,在我进行更新之前,我使用代码确保值为> = 0& < rowcount表。然后,一旦插入该值,我需要修复它创建的副本。我想要做的只是切换值。但是,当我尝试这个触发器时,我得到了可怕的oracle mutating表错误:
create or replace
trigger plantry_campus_edit_after
after update on plantry_campus
for each row
declare
v_pkid number;
begin
SELECT pkid INTO v_pkid FROM plantry_campus WHERE ord = :new.ord && pkid != :new.pkid;
UPDATE plantry_campus SET ord = :old.ord WHERE pkid = v_pkid;
end;
我更喜欢在数据库中而不是在代码中执行此操作。有关如何实现这一目标的任何建议吗?
答案 0 :(得分:1)
我会更改您的网络界面,以便他们可以在屏幕上重新排序,然后在保存时,只需按照现在屏幕上显示的顺序覆盖每行中的ord
列。
答案 1 :(得分:0)
如果要执行此操作,请尝试使用包含plsql表类型的包变量。在行触发器中填充plsql表,然后在语句触发器中执行更新。这将解决变异表问题,因为语句级触发器在此方案中不受影响。
与此相似。
problem with trigger in oracle
请记住,包变量在整个会话期间都会持续存在,因此请在之前的触发器中初始化它们。
答案 2 :(得分:0)
您可以使用视图轻松解决变异表问题;虽然它不漂亮。更新视图并触发该视图:
您需要展开触发器以包含您要更新的所有列。
create or replace view v_plantry_campus_edit as select * from plantry_campus;
create or replace
trigger plantry_campus_edit_after
after update on v_plantry_campus
for each row
declare
v_pkid number;
begin
SELECT pkid INTO v_pkid FROM plantry_campus WHERE ord = :new.ord && pkid != :new.pkid;
UPDATE plantry_campus
SET ord = :old.ord
-- etc
, col1 = :new.col1
WHERE pkid = v_pkid;
end;
答案 3 :(得分:0)
恕我直言,在这种情况下使用触发器不是一个好主意,正如@Ben所说。我会在应用程序端重新排序表格,如下所示:
显而易见:
UPDATE plantry_campus SET
ord = :new_order
where pkid = :pkid
重新订购更新:
If (:new_order > :old_order) then
UPDATE plantry_campus SET
ord = ord + 1
where pkid != :pkid
and ord >= :new_order
and ord < :old_order;
elsif (:new_order < :old_order) then
UPDATE plantry_campus SET
ord = ord - 1
where pkid != :pkid
and ord > :old_order
and ord <= :new_order;
end if;
如果您不想在应用程序中执行此操作,只需将PL / SQL函数放入包中即可。