填充NULL值

时间:2015-03-12 21:21:28

标签: sql oracle oracle11g

我正在查询特定对象的最近10天的数据:

AMT     READING_TIME            DATE
-----------------------------------------------------
                                12-MAR-15 12:00:00 AM
                                11-MAR-15 12:00:00 AM
                                10-MAR-15 12:00:00 AM
24545   09-MAR-15 10:54:00 AM   09-MAR-15 12:00:00 AM
24549   08-MAR-15 09:51:00 PM   08-MAR-15 12:00:00 AM
24549   07-MAR-15 11:37:00 PM   07-MAR-15 12:00:00 AM
24549   06-MAR-15 10:08:00 PM   06-MAR-15 12:00:00 AM
24556   05-MAR-15 11:35:00 PM   05-MAR-15 12:00:00 AM
7605    04-MAR-15 07:36:00 PM   04-MAR-15 12:00:00 AM
9631    03-MAR-15 02:20:00 PM   03-MAR-15 12:00:00 AM

READING_TIME是与AMT对应的日期。这是我们系统中的实际数据。 DATE仅仅是过去十天,今天是最重要的。在过去的3天里,我没有相应的记录,因此AMT列为NULL。请记住,这可能发生在实际上任何地方的数据集中间。

如果AMT为NULL,我希望它使用小于记录的DATE值的MAX(READING_TIME)的AMT。以下是我到目前为止所使用的内容:

SELECT
  (SELECT AMOUNT
  FROM HISTORY
  WHERE ID   = A.ID
  AND (CODE IS NOT NULL AND CODE  <> -1)
  AND TO_DATE(NVL(READING_DATE, TO_CHAR(TRANSACTION_DATE, 'YYYYMMDD'))
    || ' '
    || NVL(READING_TIME, TO_CHAR(TRANSACTION_DATE, 'HH24MI')), 'YYYYMMDD HH24MI') = A.READING_TIME
  ) AS AMOUNT,
  A.READING_TIME,
  A."DATE"
FROM
  (SELECT 329 AS ID,
    (SELECT MAX(TO_DATE(NVL(READING_DATE, TO_CHAR(TRANSACTION_DATE, 'YYYYMMDD'))
      || ' '
      || NVL(READING_TIME, TO_CHAR(TRANSACTION_DATE, 'HH24MI')), 'YYYYMMDD HH24MI')) AS READING_DATE
    FROM HISTORY TH
    WHERE TH.ID   = 329
    AND (TH.CODE IS NOT NULL AND TH.CODE  <> -1)
    AND TRUNC(TO_DATE(NVL(TH.READING_DATE, TO_CHAR(TRANSACTION_DATE, 'YYYYMMDD'))
        || ' ' || NVL(TH.READING_TIME, TO_CHAR(TRANSACTION_DATE, 'HH24MI')), 'YYYYMMDD HH24MI')) = DATES."DATE"
    ) AS READING_TIME,
    DATES."DATE"
  FROM
    (SELECT TRUNC(SYSDATE) + 1 - LEVEL AS "DATE"
     FROM DUAL
      CONNECT BY LEVEL <= 10
    ) DATES
  ) A

仅供参考,系统中的这些日期作为字符串开始,因此转换。还有一些有趣的警告,有些是NULL,所以我们使用TRANSACTION_DATE,如果是这样的话。 HISTORY表每天有多条记录。我们正在抓住特定日子的最新记录。

我的最终数据集应如下所示:

AMT     READING_TIME            DATE
-----------------------------------------------------
24545   09-MAR-15 10:54:00 AM   12-MAR-15 12:00:00 AM
24545   09-MAR-15 10:54:00 AM   11-MAR-15 12:00:00 AM
24545   09-MAR-15 10:54:00 AM   10-MAR-15 12:00:00 AM
24545   09-MAR-15 10:54:00 AM   09-MAR-15 12:00:00 AM
24549   08-MAR-15 09:51:00 PM   08-MAR-15 12:00:00 AM
24549   07-MAR-15 11:37:00 PM   07-MAR-15 12:00:00 AM
24549   06-MAR-15 10:08:00 PM   06-MAR-15 12:00:00 AM
24556   05-MAR-15 11:35:00 PM   05-MAR-15 12:00:00 AM
7605    04-MAR-15 07:36:00 PM   04-MAR-15 12:00:00 AM
9631    03-MAR-15 02:20:00 PM   03-MAR-15 12:00:00 AM

更新:这是方案的SQLFiddle

1 个答案:

答案 0 :(得分:0)

您可以使用FIRST_VALUE执行此操作。但首先,我认为你的原始查询 可以简化。

with dates(date_) as (
    select trunc(sysdate) + 1 - level
    from dual
    connect by level <= 10
    )
select 
    h.id,
    d.date_,
    max(amount) keep (dense_rank first order by coalesce(to_date(h.reading_date || h.reading_time,'yyyymmddhh24mi'), h.transaction_date) desc) amt,
    max(coalesce(to_date(h.reading_date || h.reading_time,'yyyymmddhh24mi'), h.transaction_date)) reading_time
from dates      d
left outer join history h
    on d.date_ = coalesce(to_date(h.reading_date,'yyyymmdd'),trunc(h.transaction_date))
    and h.id = 329
    and h.code <> -1 and h.code is not null
group by h.id, d.date_;

您可以在一次扫描中完成两次扫描,而不是扫描表格。

  1. 如果READ_date / reading_time同时为null或不为null,则可以简化派生列reading_time。
  2. FIRST函数用于获取与最大阅读时间相对应的金额。
  3. 完成后,应用FIRST_VALUE函数。

    with dates(date_) as (
        select trunc(sysdate) + 1 - level
        from dual
        connect by level <= 10
        )
    select 
        first_value(amt) ignore nulls over (order by date_ desc rows between current row and unbounded following) amt,
        first_value(reading_time) ignore nulls over (order by date_ desc rows between current row and unbounded following) reading_time,
        date_
    from (
        select 
            h.id,
            d.date_,
            max(amount) keep (dense_rank first order by coalesce(to_date(h.reading_date || h.reading_time,'yyyymmddhh24mi'), h.transaction_date) desc) amt,
            max(coalesce(to_date(h.reading_date || h.reading_time,'yyyymmddhh24mi'), h.transaction_date)) reading_time
        from dates      d
        left outer join history h
            on d.date_ = coalesce(to_date(h.reading_date,'yyyymmdd'),trunc(h.transaction_date))
            and h.id = 329
            and h.code <> -1 and h.code is not null
        group by h.id, d.date_
        )
    order by date_ desc;
    

    示例:

    SQL> select * from myt order by date_ desc;
    
           AMT READING_TIME               DATE_
    ---------- -------------------------- --------------------------
                                          12-MAR-2015 00:00:00
                                          11-MAR-2015 00:00:00
                                          10-MAR-2015 00:00:00
         24545 09-MAR-2015 10:54:00       09-MAR-2015 00:00:00
         24549 08-MAR-2015 21:51:00       08-MAR-2015 00:00:00
         24549 07-MAR-2015 23:37:00       07-MAR-2015 00:00:00
                                          06-MAR-2015 00:00:00
         24556 05-MAR-2015 23:35:00       05-MAR-2015 00:00:00
          7605 04-MAR-2015 19:36:00       04-MAR-2015 00:00:00
          9631 03-MAR-2015 14:20:00       03-MAR-2015 00:00:00
    
    10 rows selected.
    
    SQL> select 
    first_value(amt) ignore nulls over (order by date_ desc rows between current row and unbounded following) amt,
    first_value(reading_time) ignore nulls over (order by date_ desc rows between current row and unbounded following) reading_time,
    date_
    from myt order by date_ desc;
      2    3    4    5  
           AMT READING_TIME               DATE_
    ---------- -------------------------- --------------------------
         24545 09-MAR-2015 10:54:00       12-MAR-2015 00:00:00
         24545 09-MAR-2015 10:54:00       11-MAR-2015 00:00:00
         24545 09-MAR-2015 10:54:00       10-MAR-2015 00:00:00
         24545 09-MAR-2015 10:54:00       09-MAR-2015 00:00:00
         24549 08-MAR-2015 21:51:00       08-MAR-2015 00:00:00
         24549 07-MAR-2015 23:37:00       07-MAR-2015 00:00:00
         24556 05-MAR-2015 23:35:00       06-MAR-2015 00:00:00
         24556 05-MAR-2015 23:35:00       05-MAR-2015 00:00:00
          7605 04-MAR-2015 19:36:00       04-MAR-2015 00:00:00
          9631 03-MAR-2015 14:20:00       03-MAR-2015 00:00:00
    
    10 rows selected.
    

    sqlfiddle