所以数据是这样的:
ID | START_DATE | END_DATE | UID | CANCELED
-------------------------------------------------
44 | 2015-10-20 22:30 | 2015-10-20 23:10 | 'one' |
52 | 2015-10-20 23:00 | 2015-10-20 23:30 | 'one' |
66 | 2015-10-21 13:00 | 2015-10-20 13:30 | 'two' |
这些条目超过10万。
我们可以看到第二个条目的start_date与第一个条目的end_date重叠。当日期重叠时,具有较低ID的条目应在“取消”列中标记为真。
我尝试了一些查询,但是他们花了很长时间,所以即使他们工作我也不确定。此外,我想覆盖所有重叠的案例,所以这似乎也减慢了这一点。
我是负责使用pl / sql
插入/更新这些条目的人update table set column = 'value' where ID = '44';
if sql%rowcount = 0
then insert values(...)
end if
所以我可以在这一步中做到这一点。但是所有的表都是使用动态创建的一个大的pl / sql进行更新/插入的,其中所有行都会更新或者新的行被插入,所以这似乎再次变慢。
在所有sql'方言'oracle中,我有机会使用它是最神秘的。想法?
编辑:我忘了一个重要的细节,还有一个要匹配的列(UID),上面更新答案 0 :(得分:1)
我认为以下更新应该有效:
update tbl
set cancelled = 'TRUE'
where t_id in (select t_id
from tbl t
where exists (select 1
from tbl x
where x.t_id > t.t_id
and x.start_date <= t.end_date));
小提琴: http://sqlfiddle.com/#!4/06447/1/0
如果表格非常大,您可能最好使用CTAS(创建表格为选择)查询创建新表格,您可以使用nologging
选项,以避免必须写入撤消日志。当您执行类似于现在的更新时,您正在将更改写入Oracle的撤消日志,以便在提交事务之前,您可以选择回滚。这增加了开销。因此,带有nologging的CTAS查询可能会运行得更快。这是这种方法的一种方式:
create table new_table nologging as
with sub as
(select t_id,
start_date,
end_date,
'TRUE' as cancelled
from tbl t
where exists (select 1
from tbl x
where x.t_id > t.t_id
and x.start_date <= t.end_date))
select *
from sub
union all
select t.*
from tbl t
left join sub s
on t.t_id = s.t_id
where s.t_id is null;
答案 1 :(得分:1)
我会从这个查询开始:
update table t
set cancelled = true
where exists (select 1
from table t2
where t.end_date > t2.start_date and
t.uid = t2.uid and
t.id < t2.id
)
table(uid, start_date, id)
上的索引可能会有所帮助。
注意:创建表格时,这可能更容易 ,因为您可以使用lag()
。
答案 2 :(得分:1)
这将在没有动态查询或相关子查询的情况下完成,但它为 MERGE INTO Table1
USING
(
with q0 as(
select rownum fid, id, start_date from(
select id, start_date from table1
union all
select 999999 id, null start_date from dual
order by id
)
), q1 as (
select rownum fid, id, end_date from(
select -1 id, null end_date from dual
union all
select id, end_date from table1
order by id
)
)
select q0.fid, q1.id, q0.start_date, q1.END_DATE, case when (q0.start_date < q1.END_DATE) then 1 else 0 end canceled
from q0
join q1
on (q0.fid = q1.fid)
) ta ON (ta.id = Table1.id)
WHEN MATCHED THEN UPDATE
SET Table1.canceled = ta.canceled;
子句消耗了一些内存:
with
带有别名select
的内部ta
"FID"|"ID"|"START_DATE" |"END_DATE" |"CANCELED"
---------------------------------------------------------
1 |-1 |20/10/15 22:30:00| |0
2 |44 |20/10/15 23:00:00|20/10/15 23:10:00|1
3 |52 |21/10/15 13:00:00|20/10/15 23:30:00|0
4 |66 | |20/10/15 13:30:00|0
语句会产生以下结果:
merge
然后在{{1}} v中使用它而没有任何相关查询。使用SQLDeveloper进行了测试和工作。
答案 3 :(得分:1)
您可以使用BULK COLLECT INTO
和FORALL
来减少过程中的上下文切换:
Oracle 11g R2架构设置:
CREATE TABLE test ( ID, START_DATE, END_DATE, CANCELED ) AS
SELECT 44, TO_DATE( '2015-10-20 22:30', 'YYYY-MM-DD HH24:MI' ), TO_DATE( '2015-10-20 23:10', 'YYYY-MM-DD HH24:MI' ), 'N' FROM DUAL
UNION ALL SELECT 52, TO_DATE( '2015-10-20 23:00', 'YYYY-MM-DD HH24:MI' ), TO_DATE( '2015-10-20 23:30', 'YYYY-MM-DD HH24:MI' ), 'N' FROM DUAL
UNION ALL SELECT 66, TO_DATE( '2015-10-21 13:00', 'YYYY-MM-DD HH24:MI' ), TO_DATE( '2015-10-21 12:30', 'YYYY-MM-DD HH24:MI' ), 'N' FROM DUAL
/
CREATE PROCEDURE updateCancelled
AS
TYPE ids_t IS TABLE OF test.id%TYPE INDEX BY PLS_INTEGER;
t_ids ids_t;
BEGIN
SELECT ID
BULK COLLECT INTO t_ids
FROM (
SELECT ID,
END_DATE,
LEAD( START_DATE ) OVER ( ORDER BY START_DATE ) AS NEXT_START_DATE
FROM TEST )
WHERE END_DATE > NEXT_START_DATE;
FORALL i IN 1 .. t_ids.COUNT
UPDATE TEST
SET CANCELED = 'Y'
WHERE ID = t_ids(i);
END;
/
BEGIN
updateCancelled();
END;
/
查询1 :
SELECT * FROM TEST
<强> Results 强>:
| ID | START_DATE | END_DATE | CANCELED |
|----|---------------------------|---------------------------|----------|
| 44 | October, 20 2015 22:30:00 | October, 20 2015 23:10:00 | Y |
| 52 | October, 20 2015 23:00:00 | October, 20 2015 23:30:00 | N |
| 66 | October, 21 2015 13:00:00 | October, 21 2015 12:30:00 | N |
或者作为单个SQL语句:
UPDATE TEST
SET CANCELED = 'R'
WHERE ID IN ( SELECT ID
FROM ( SELECT ID,
END_DATE,
LEAD( START_DATE )
OVER ( ORDER BY START_DATE )
AS NEXT_START_DATE
FROM TEST )
WHERE END_DATE > NEXT_START_DATE )