SQL Fiddle上的整个设置:http://sqlfiddle.com/#!4/1fd0e/5
我有一些数据包含人员ID,级别和级别日期范围,如下所示:
PID LVL START_DATE END_DATE
1 1 01.01.14 19.03.14
1 2 20.03.14 15.08.14
1 3 16.08.14 09.10.14
1 4 10.10.14 31.12.14
2 1 01.01.14 31.12.14
3 1 01.01.14 16.01.14
我需要将开始日期设置为月份的第一天,将结束日期设置为月份的最后一天。最后一天规则仅适用于,如果它不是该人的最后一行数据。
我到目前为止所做的事情:
select
pid, lvl,
trunc(start_date, 'month') as start_date,
case when lead(pid, 1) over (PARTITION BY pid order by end_date) is not null
then last_day(add_months(end_date, -1))
else last_day(end_date)
end as end_date
from date_tbl t;
给了我想要的输出:
PID LVL START_DATE END_DATE
1 1 01.01.14 28.02.14
1 2 01.03.14 31.07.14
1 3 01.08.14 30.09.14
1 4 01.10.14 31.12.14
2 1 01.01.14 31.12.14
3 1 01.01.14 31.01.14
但是它适用于我的测试数据。关于包含25k +行数据的表格上的生产数据(我说的数据不是太多),它的执行速度非常慢。
任何人都可以提示我如何提高查询的性能吗?例如,在哪些列上设置哪些索引?到目前为止唯一的索引列是PID列。
答案 0 :(得分:0)
实际上,据我所知,如果一个人只有一条记录,那么你的脚本会产生错误的结果(pid = 3的情况)
拜托,你能试试这个吗?
select
pid,
lvl,
trunc(start_date, 'month') as start_date,
last_day(add_months(end_date, case when lvl = max(lvl) over (partition by pid) then 0 else -1 end)) end_date
from date_tbl t;
我猜你需要为列构建索引(pid,lvl desc)
答案 1 :(得分:0)
好的伙计们,抱歉等你的时间。简而言之:这是我的错。在我的过程中,上面的查询对某个子查询中的另一个表进行LEFT JOIN:
with dates as (
select
pid, lvl,
trunc(start_date, 'month') as start_date,
case when lead(pid, 1) over (PARTITION BY pid order by end_date) is not null
then last_day(add_months(end_date, -1))
else last_day(end_date)
end as end_date
from date_tbl t
),
some_other_table as (
select pid, (...some more columns)
from other_table
)
select * from (
select
b.pid, -- <== this has to be a.pid. b is much bigger than a!
a.start_date,
a.end_date
from dates a left join some_other_table b on a.pid = b.pid
)
整个查询要大得多。
@jonearles thx为您的评论。 “什么是完整的查询?”帮助我回到正轨:将查询拆分成碎片并再次检查真正减慢它的速度。