填充 NULL 值

Filling the NULL values

我正在为特定对象查询最近 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 table 每天有多条记录。我们正在获取特定日期的最新记录。

我的最终数据集应该是这样的:

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场景

您可以使用 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_;

无需扫描 table 两次,您可以扫描一次。

  1. 可以简化派生列 reading_time,假设 reading_date/reading_time 同时为 null 或不为 null。
  2. FIRST函数用于获取最长阅读时间对应的金额

完成后,应用 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