ID Name Time Status
1 A 5 0
2 B 6 0
3 C 7 0
4 D 10 0
让我们说N = 2,我需要找出时间5和10之间是否存在2条记录。在这种情况下,id为2&的记录。 3.如果存在记录,我必须将这些记录的状态更新为1。
可能的选择。 BULK将id收集到一些临时PLSQL集合中,如果该集合的大小大于2,则更新这些ID的状态。
有没有更好的方法而没有两次击中桌子?
答案 0 :(得分:2)
在PL / SQL中,无论如何都可以进行更新,如果sql%rowcount
不是2,则可以撤消更新。
create or replace procedure p1
( p_start date
, p_end date )
as
begin
savepoint before_update;
update demo set indicator = 'Y'
where dt between p_start and p_end
and rownum < 4; -- limit here as we will be rolling back if 3 or more anyway
dbms_output.put('Updated ' || sql%rowcount || ' row(s)');
if sql%rowcount <> 2 then
rollback to before_update;
dbms_output.put_line(' but rolled back');
else
dbms_output.new_line;
end if;
end p1;
演示(Oracle 12.1):
create table demo (dt date not null, indicator varchar2(1));
insert all
into demo values (date '2018-01-01', null)
into demo values (date '2018-02-01', null)
into demo values (date '2018-03-01', null)
into demo values (date '2018-03-09', null)
into demo values (date '2018-04-01', null)
into demo values (date '2018-05-01', null)
select * from dual;
call p1(date '2018-01-01', date '2018-06-01');
-- Updated 3 row(s) but rolled back
call p1(date '2018-03-01', date '2018-03-31');
-- Updated 2 row(s)
答案 1 :(得分:1)
我会在这里使用merge
:
merge into tbl
using (select id, count(1) over () cnt from tbl where 5 < time and time < 10) src
on (tbl.id = src.id and cnt >= 2)
when matched then update set status = 1;
..或者如果您出于某种原因更喜欢PLSQL和bulk collect
:
declare
v_ids sys.odcinumberlist;
begin
select id
bulk collect into v_ids
from (select id, count(1) over () cnt from tbl where 5 < time and time < 10)
where cnt >= 2;
forall i in 1..v_ids.count
update tbl set status = 1 where id = v_ids(i);
end;
示例数据:
create table tbl(id, name, time, status) as
select 1, 'A', 5, 0 from dual union all
select 2, 'B', 6, 0 from dual union all
select 3, 'C', 7, 0 from dual union all
select 4, 'D', 10, 0 from dual;
merge
之后的结果或执行阻止:
ID NAME TIME STATUS
------ ---- ---------- ----------
1 A 5 0
2 B 6 1
3 C 7 1
4 D 10 0
答案 2 :(得分:0)
这对我来说是一个奇怪的要求。但您可以使用where
子句中的子查询来执行此操作:
update t
set status = 1
where t.time > 5 and t.time < 10 and
(select count(*) from t where t.time > 5 and t.time < 10) >= 2