日期范围和异常值

时间:2013-05-30 13:33:05

标签: sql oracle

我将尝试解释这个(简化)......

我有一个查询,主要使用数据范围作为限定符从表中收集数据;

select parent_order_id, order_id, order_dt_tm
from orders
where order_dt_tm between to_date("2013-05-30 00:00:00", 'YYYY-MM-DD HH24:MI:SS') AND to_date("2013-05-30 23:59:59")

因此,order_id是唯一的,而parent_order_id有许多子order_id

parent_order_id    order_id    order_dt_tm
---------------    --------    -----------
111.00             112.00      2013-05-29 06:00:00
111.00             113.00      2013-05-29 18:00:00
111.00             114.00      2013-05-30 06:00:00
111.00             115.00      2013-05-30 18:00:00  
111.00             116.00      2013-05-31 06:00:00
111.00             117.00      2013-05-31 18:00:00

我的问题是我需要上述查询的结果加上我的日期之前的最高结果和我结束日期之后的最低结果。基本上我想要我的结果集;

parent_order_id    order_id    order_dt_tm
---------------    --------    -----------
111.00             113.00      2013-05-29 18:00:00
111.00             114.00      2013-05-30 06:00:00
111.00             115.00      2013-05-30 18:00:00  
111.00             116.00      2013-05-31 06:00:00

我不知道运行时的日期范围或异常值的限定符,我必须只传递最高和最低。

此表上有很多数据,我尝试过以下内容以获得之前的最高值。

select parent_order_id, order_id, order_dt_tm
from orders
where order_dt_tm between to_date("2013-05-30 00:00:00", 'YYYY-MM-DD HH24:MI:SS') AND to_date("2013-05-30 23:59:59")
    or order_id = 
             (select distinct FIRST_VALUE(order_id) OVER (PARTITION BY parent_order_id ORDER BY order_id DESC
             from orders
             where order_dt_tm < to_date("2013-05-30 00:00:00", 'YYYY-MM-DD HH24:MI:SS')
             )

问题是;它是SLOW ... 5M +行的表中的父查询及其所有其他的quals都很快。 order_dt_tm是索引的一部分。但是无论我采用何种方式来获得异常值,它都变得非常缓慢。

此外,我不确定我是否总能确定order_id是该日期的最高值。真的应该按日期和时间来实现。

感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

最有效的查询可能是这样的:

-- last row of previous day
SELECT parent_order_id, order_id, order_dt_tm
  FROM (SELECT parent_order_id, order_id, order_dt_tm
          FROM orders
         WHERE order_dt_tm < :date_start
         ORDER BY order_dt_tm DESC)
  WHERE ROWNUM = 1)
UNION ALL
<your_query>
UNION ALL
-- first row of the next day
SELECT parent_order_id, order_id, order_dt_tm
  FROM (SELECT parent_order_id, order_id, order_dt_tm
          FROM orders
         WHERE order_dt_tm > :date_end
         ORDER BY order_dt_tm)
  WHERE ROWNUM = 1)

我认为order_dt_tm上的单个常规索引可以用于第一个和最后一个子查询,以执行非常有效的单行范围扫描。

答案 1 :(得分:0)

我会使用lag and lead

select parent_order_id, order_id, order_dt_tm
from
(
    select parent_order_id
    ,      order_id
    ,      order_dt_tm
    ,      lag(order_dt_tm) over (order by order_dt_tm)  prev_order_dt_tm
    ,      lead(order_dt_tm) over (order by order_dt_tm) next_order_dt_tm
    from   orders
)
where  next_order_dt_tm >= to_date('2013-05-30 00:00:00', 'YYYY-MM-DD HH24:MI:SS')  -- start_date of range
and    prev_order_dt_tm <= to_date('2013-05-30 23:59:59', 'YYYY-MM-DD HH24:MI:SS')  -- end_date of range