填充 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 两次,您可以扫描一次。
- 可以简化派生列 reading_time,假设 reading_date/reading_time 同时为 null 或不为 null。
- 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.
我正在为特定对象查询最近 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 两次,您可以扫描一次。
- 可以简化派生列 reading_time,假设 reading_date/reading_time 同时为 null 或不为 null。
- 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.