SQL> select LAST_UPDATED_DATE, ODOMETER from demo; LAST_UPDA ODOMETER --------- ---------- 05-OCT-18 47174.77 08-OCT-18 12-OCT-18 50246.37 15-OCT-18 19-OCT-18 53743.11 21-OCT-18 22-OCT-18 25-OCT-18 58789.22 8 rows selected.
我需要确定里程表的值(其中它为null),这必须使用SQL来完成。我当时想的方法是-
例如在这种情况下(50246.37-47174.77)/(12-OCT-18-05-OCT-18)=〜439
例如,(08-OCT-18-05-OCT-18)= 3天,并且连续3天439 * 3 =1317。因此,08年10月18日的值可以是47174.77 + 1317 = 48491.77 >
现在,我需要为此编写SQL代码的帮助。
任何帮助将不胜感激。
答案 0 :(得分:2)
您可以使用累积的最大值和最小值来获得上一行和下一行(这假设里程表仅沿一个方向运行)。其余只是算术插值的算术运算:
select d.last_updated_date, d.odometer,
(case when d.odometer is not null then d.odometer
else prev_o + (next_o - prev_o) * (last_updated_date - prev_lud) / (next_lud - prev_lud)
end)
from (select d.*,
max(case when odometer is not null then last_updated_date end) over (order by last_updated_date) as prev_lud,
max(odometer) over (order by last_updated_date) as prev_o,
min(case when odometer is not null then last_updated_date end) over (order by last_updated_date desc) as next_lud,
min(odometer) over (order by last_updated_date desc) as next_o
from demo d
) d;
答案 1 :(得分:2)
这就是我要做的。这可能有助于解决其他类似问题(线性插值),在这些问题中不能假定“值”随时间增加。对于里程表而言,该假设非常合理,而戈登·利诺夫(Gordon Linoff)的解决方案更简单。我为“数量”可能随时间上升或下降的其他应用程序提供此解决方案。
with
sample_data(last_updated_date, odometer) as (
select to_date('05-OCT-18', 'dd-MON-rr'), 47174.77 from dual union all
select to_date('08-OCT-18', 'dd-MON-rr'), null from dual union all
select to_date('12-OCT-18', 'dd-MON-rr'), 50246.37 from dual union all
select to_date('15-OCT-18', 'dd-MON-rr'), null from dual union all
select to_date('19-OCT-18', 'dd-MON-rr'), 53743.11 from dual union all
select to_date('21-OCT-18', 'dd-MON-rr'), null from dual union all
select to_date('22-OCT-18', 'dd-MON-rr'), null from dual union all
select to_date('25-OCT-18', 'dd-MON-rr'), 58789.22 from dual
)
, prep(last_updated_date, odometer, prev_date, next_date, prev_odo, next_odo) as (
select last_updated_date, odometer,
case when odometer is null
then max(nvl2(odometer, last_updated_date, null))
over (order by last_updated_date) end,
case when odometer is null
then min(nvl2(odometer, last_updated_date, null))
over (order by last_updated_date
rows between 1 following and unbounded following) end,
last_value(odometer ignore nulls) over (order by last_updated_date),
first_value(odometer ignore nulls) over (order by last_updated_date
rows between 1 following and unbounded following)
from sample_data
)
select last_updated_date,
nvl( odometer,
round(prev_odo + (next_odo - prev_odo) *
(last_updated_date - prev_date) / (next_date - prev_date), 2)
) as odometer
from prep
order by last_updated_date
;
输出
LAST_UPDATED_DATE ODOMETER
----------------- ----------
05-OCT-18 47174.77
08-OCT-18 48491.17
12-OCT-18 50246.37
15-OCT-18 51744.97
19-OCT-18 53743.11
21-OCT-18 55425.15
22-OCT-18 56266.17
25-OCT-18 58789.22
答案 2 :(得分:1)
这是一个查询,它将为您提供缺少的值。它使用两个常规联接来找到里程表值可用的上一条和下一条记录。
SELECT
d.last_update_date,
d0.odometer
+ (d1.odometer - d0.odometer) * ( d.last_update_date - d0.last_update_date )
/ ( d1.last_update_date - d0.last_update_date ) odometer
FROM
demo d
INNER JOIN demo d0 ON d0.last_update_date = (
SELECT MAX(last_update_date)
FROM demo
WHERE odometer IS NOT NULL AND last_update_date < d.last_update_date
)
INNER JOIN demo d1 ON d1.last_update_date = (
SELECT MIN(last_update_date)
FROM demo
WHERE odometer IS NOT NULL AND last_update_date > d.last_update_date
)
WHERE d.odometer IS NULL;
此 DB Fiddle demo 返回:
LAST_UPDATE_DATE | ODOMETER
:--------------- | ----------:
08-OCT-18 | 48491.17
15-OCT-18 | 51744.97
21-OCT-18 | 55425.15
22-OCT-18 | 56266.17
10月8日的值似乎正是您所期望的值。
如果要实际更新表以添加缺少的值,则可以使用Oracle MERGE
语法,如下所示: this db fiddle :
MERGE INTO demo target
USING (
SELECT
d.last_update_date,
d0.odometer
+ (d1.odometer - d0.odometer) * ( d.last_update_date - d0.last_update_date )
/ ( d1.last_update_date - d0.last_update_date ) odometer
FROM
demo d
INNER JOIN demo d0 ON d0.last_update_date = (
SELECT MAX(last_update_date)
FROM demo
WHERE odometer IS NOT NULL AND last_update_date < d.last_update_date
)
INNER JOIN demo d1 ON d1.last_update_date = (
SELECT MIN(last_update_date)
FROM demo
WHERE odometer IS NOT NULL AND last_update_date > d.last_update_date
)
WHERE d.odometer IS NULL
) src ON (src.last_update_date = target.last_update_date)
WHEN MATCHED THEN UPDATE SET target.odometer = src.odometer;
答案 3 :(得分:0)
您可以使用OUTER APPLY
(从Oracle 12c开始)使用ODOMETER获取上一行和下一行。然后使用公式进行线性插值。
select
demo.last_updated_date,
coalesce
(
demo.odometer,
prev.odometer + ( (next.odometer - prev.odometer) *
(demo.last_updated_date - prev.last_updated_date) /
(next.last_updated_date - prev.last_updated_date) )
) as odometer
from demo
outer apply
(
select *
from demo d
where d.last_updated_date < demo.last_updated_date
and d.odometer is not null
order by d.last_updated_date desc
fetch first row only
) prev
outer apply
(
select *
from demo d
where d.last_updated_date > demo.last_updated_date
and d.odometer is not null
order by d.last_updated_date desc
fetch first row only
) next
order by demo.last_updated_date;
结果(四舍五入):
LAST_UPDATED_DATE | ODOMETER ------------------+--------- 05-OCT-18 | 47174.77 08-OCT-18 | 48916.94 12-OCT-18 | 50246.37 15-OCT-18 | 52217.80 19-OCT-18 | 53743.11 21-OCT-18 | 55425.15 22-OCT-18 | 56266.17 25-OCT-18 | 58789.22
演示:https://dbfiddle.uk/?rdbms=oracle_18&fiddle=54cc9d4b7dd5793e1c0025627fd929de