如何有效地涂抹查询结果

时间:2015-05-18 13:12:20

标签: sql oracle

给定一个包含两列的表格,一个独特的增加ID和一个Transaction_Date就是它的样子。我想找到每小时的第一个ID,包括没有交易的时间。

尝试使用Oracle我有:

WITH parameters AS(
        SELECT  TO_DATE('01/03/2015','DD/MM/YYYY') AS START_DAY
        ,       TO_DATE('08/03/2015','DD/MM/YYYY') AS END_DAY
        FROM    DUAL
), hour_range AS(
        SELECT  START_DAY + (LEVEL-1)/24 AS DT
        FROM    PARAMETERS
        CONNECT BY LEVEL <= (END_DAY - START_DAY + 1)*24 
)
SELECT TO_CHAR(HOUR_RANGE.DT,'DD-MON-YYYY HH24:"00"'),
MIN (T.Transaction_ID)
FROM HOUR_RANGE
LEFT JOIN Transactions T ON T.Transaction_Date > DT
GROUP BY TO_CHAR(HOUR_RANGE.DT,'DD-MON-YYYY HH24:"00"')
ORDER BY 1;

这似乎需要花费大量时间才能运行,即使在Transaction_IDTransaction_Date上有索引。

有更好的方法吗?

尝试更好的方式 - 仍然需要很长时间:

with parameters as(
        select  to_date('01/03/2015','dd/mm/yyyy') as start_day
        ,       to_date('08/03/2015','dd/mm/yyyy') as end_day
        from    dual
), hour_range as(
        select  start_day + (level-1)/24 as dt
        from    parameters
        connect by level <= (end_day - start_day + 1)*24 
), tx as(
        select  to_char(rt.transaction_date,'dd-mon-yyyy hh24:"00"') tx_time,
                min(rt.transaction_id) min_tx_id
        from    Transactions rt
        join    hour_range   on rt.transaction_date >= hour_range.dt and
                                rt.transaction_date <  hour_range.dt + (1/24)
        group by to_char(rt.transaction_date,'dd-mon-yyyy hh24:"00"'))

select to_char(h.dt,'dd-mon-yyyy hh24:"00"'),
       t.min_tx_id
from      hour_range h
left join tx t on t.tx_time = h.dt
order by 1;

这是基于@DavidAldridge的建议和一些调整(我希望我有正确的),因为我忘了解释日期是TimeStamp。不知道它是否有效,因为它还没有完成。

2 个答案:

答案 0 :(得分:2)

考虑一下:

LEFT JOIN Transactions T ON T.Transaction_Date > DT

每小时记录都会加入到大于它的每个交易记录中。

你想要的是:

LEFT JOIN Transactions T ON T.Transaction_Date >= DT and     
                            T.Transaction_Date <  DT + (1/24)

此外,您可以考虑在加入小时列表之前通过trunc(transaction_date,&#39; HH&#39;)汇总交易记录,然后您可以发出qui-join。

类似的东西:

with
  parameters as
    (select  to_date('01/03/2015','dd/mm/yyyy') as start_day,
             to_date('08/03/2015','dd/mm/yyyy') as end_day
     from    dual),
  hour_range as
    (select  start_day + (level-1)/24 as dt
     from    parameters
     connect by level <= (end_day - start_day + 1)*24),
  tx as
   (select  trunc(transaction_date, 'hh') tx_hour,
            min(t.transaction_id) min_tx_id
    from    transactions
    join    parameters   on transaction_date >= start_day and
                            transaction_date <  end_day
    group by trunc(transaction_date, 'hh'))
select    to_char(hour_range.dt,'dd-mon-yyyy hh24:"00"'),
          min_tx_id
from      hour_range h
left join tx         t on t.transaction_date = h.dt
group by  to_char(hour_range.dt,'dd-mon-yyyy hh24:"00"')
order by  1;

答案 1 :(得分:0)

我希望尽早过滤,所以我会在加入生成的小时列表之前完成小组,例如:

WITH parameters AS (SELECT  TO_DATE('01/03/2015','DD/MM/YYYY') AS START_DAY,
                            TO_DATE('08/03/2015','DD/MM/YYYY') AS END_DAY
                    FROM    DUAL),
     hour_range AS (SELECT  START_DAY + (LEVEL-1)/24 AS DT
                    FROM    PARAMETERS
                    CONNECT BY LEVEL <= (END_DAY - START_DAY + 1)*24),
        results as (select trunc(dt, 'hh24') hr,
                           min(transaction_id) id
                    from   hour_range
                    where  dt between (select start_day from parameters) and (select end_day from parameters)
                    group by trunc(dt, 'hh24'))
select to_char(hrg.dt, 'DD-MON-YYYY hh24:mm') dt,
       res.id
from   hour_range hrg
       left outer join results res on (hrg.dt = res.hr);