Wil*_*son 5 oracle oracle-12c computed-column date-math
我road_condition
在Oracle 12c 中有一张表:
create table road_condition (
cond_id number(5,0),
road_id number(5,0),
cond_date date,
condition number(5,0)
);
insert into road_condition (cond_id,road_id,cond_date,condition)
values (1,100,to_date('01-NOV-84','DD-MON-RR'),18);
insert into road_condition (cond_id,road_id,cond_date,condition)
values (2,100,to_date('01-JAN-09','DD-MON-RR'),6);
insert into road_condition (cond_id,road_id,cond_date,condition)
values (3,100,to_date('19-JUN-12','DD-MON-RR'),4);
insert into road_condition (cond_id,road_id,cond_date,condition)
values (4,100,to_date('29-APR-15','DD-MON-RR'),4);
insert into road_condition (cond_id,road_id,cond_date,condition)
values (5,200,to_date('29-APR-92','DD-MON-RR'),20);
insert into road_condition (cond_id,road_id,cond_date,condition)
values (6,200,to_date('05-APR-17','DD-MON-RR'),3);
commit;
Run Code Online (Sandbox Code Playgroud)
结果表数据:
COND_ID ROAD_ID COND_DAT CONDITION
------- ------- -------- ---------
1 100 84-11-01 18
2 100 09-01-01 6
3 100 12-06-19 4
4 100 15-04-29 4
5 200 92-04-29 20
6 200 17-04-05 3
Run Code Online (Sandbox Code Playgroud)
这是一张道路图#100
:
Condition
表中的分类如下:
Condition
是从0 到 20, 20 是一条完美的道路。
检查道路时,条件存储为整数(整数),而不是小数。
题:
我不想将图中的线条显示为单一颜色(蓝色),而是想将线条作为彩色类别进行条纹化。
我road #100
在 Excel 中模拟过:
主意:
要按所述对数据进行条带化/分类,我想我需要在沿线的每个范围的开始和结束处创建虚拟点(行)。
也许最简单的方法是在条件的所有间隔处创建点(行),而不仅仅是在每个范围的开始和结束处。
我使用的绘图软件会在图表中为每个 Y 列/系列创建一条新线(类似于 Excel 的方式)。
因此,我相信我需要将每个类别隔离在单独的列中,以便将其绘制为单独的线(具有单独的颜色)。
此外,每个类别之间需要重叠,以便绘图软件不会显示线条之间的间隙。
如何创建虚拟行(插入日期)?
更新:
我在这里有一个相关的问题:日期为 x 轴:如何乘除日期?
玩得开心。
with
num_years as (select extract(year from max(cond_date)) - extract(year from min(cond_date)) +1 as years from road_condition where road_id = 100),
generated_dates as (select add_months(trunc((select min(cond_date) from road_condition where road_id = 100), 'YYYY'), (rownum - 1) * 12) as cond_date from dual connect by level <= (select years from num_years)),
generated_data as (select rc.cond_id, rc.road_id,nvl(rc.cond_date, gd.cond_date) as cond_date, rc.condition
from generated_dates gd left join (select * from road_condition where road_id = 100) rc on (gd.cond_date = trunc(rc.cond_date, 'YYYY'))
),
data1 as (select
last_value(cond_id ignore nulls) over (order by cond_date) as cond_id,
cond_id as original_cond_id,
road_id, cond_date, condition,
last_value(condition ignore nulls) over (order by cond_date) as s1,
lead(condition ignore nulls) over (order by cond_date) as s2
from generated_data
),
data2 as (
select
cond_id, road_id, original_cond_id, cond_date, condition, s1, s2,
count(*) over (partition by cond_id) + 1 as s,
count(*) over (partition by cond_id order by cond_date rows between unbounded preceding and current row) as s0
from data1
),
data3 as (
select original_cond_id as cond_id, road_id, cond_date,
round(nvl(condition, (1-s0/s)*(s1-s2)+s2)) as condition
from data2
),
final_data as (
select cond_id, road_id, cond_date,
case when condition between 15 and 20 then condition end as cond_good,
case when condition between 11 and 14 then condition end as cond_overlay,
case when condition between 8 and 10 then condition end as cond_fdr,
case when condition between 0 and 7 then condition end as cond_recon
from data3
),
data_for_graph as
(
select
cond_id, road_id, cond_date, cond_good,
case when cond_good is not null and lead(cond_overlay) over (order by cond_date) is not null then cond_good else cond_overlay end as cond_overlay,
case when cond_overlay is not null and lead(cond_fdr) over (order by cond_date) is not null then cond_overlay else cond_fdr end as cond_fdr,
case when cond_fdr is not null and lead(cond_recon) over (order by cond_date) is not null then cond_fdr else cond_recon end as cond_recon
from final_data
)
select * from data_for_graph order by cond_date;
Run Code Online (Sandbox Code Playgroud)
输出:
COND_ID ROAD_ID COND_DATE COND_GOOD COND_OVERLAY COND_FDR COND_RECON
---------- ---------- ---------- ---------- ------------ ---------- ----------
1 100 1984-11-01 18
1985-01-01 17
1986-01-01 17
1987-01-01 16
1988-01-01 16
1989-01-01 15
1990-01-01 15 15
1991-01-01 14
1992-01-01 14
1993-01-01 13
1994-01-01 13
1995-01-01 12
1996-01-01 12
1997-01-01 12
1998-01-01 11
1999-01-01 11 11
2000-01-01 10
2001-01-01 10
2002-01-01 9
2003-01-01 9
2004-01-01 8
2005-01-01 8 8
2006-01-01 7
2007-01-01 7
2008-01-01 6
2 100 2009-01-01 6
2010-01-01 5
2011-01-01 5
3 100 2012-06-19 4
2013-01-01 4
2014-01-01 4
4 100 2015-04-29 4
Run Code Online (Sandbox Code Playgroud)
您可以按照我列出的顺序从最后一行中的 CTE 中进行选择(so select * from num_years
、 then select * from generated_dates
、 thenselect * from generated_data
等等),从而按照步骤进行操作。
我想我可能已经用这种相对简单的方法破解了它。
它假设道路寿命已知,而不是状况日期。更多信息请参见:日期作为 x 轴:如何乘除日期?
它使用简单的数学来获取线串每段的斜率和 y 轴截距。然后交叉连接到数字表(条件数字)以在每个条件间隔生成点。
create table numbers_condition
(
numbers number(4,0)
);
insert into numbers_condition numbers values (20);
insert into numbers_condition numbers values (19);
insert into numbers_condition numbers values (18);
insert into numbers_condition numbers values (17);
insert into numbers_condition numbers values (16);
insert into numbers_condition numbers values (15);
insert into numbers_condition numbers values (14);
insert into numbers_condition numbers values (13);
insert into numbers_condition numbers values (12);
insert into numbers_condition numbers values (11);
insert into numbers_condition numbers values (10);
insert into numbers_condition numbers values (9);
insert into numbers_condition numbers values (8);
insert into numbers_condition numbers values (7);
insert into numbers_condition numbers values (6);
insert into numbers_condition numbers values (5);
insert into numbers_condition numbers values (4);
insert into numbers_condition numbers values (3);
insert into numbers_condition numbers values (2);
insert into numbers_condition numbers values (1);
insert into numbers_condition numbers values (0);
commit;
Run Code Online (Sandbox Code Playgroud)
with a as
(
select
cond_id,
road_id,
x1,
y1,
x2,
y2,
(y2-y1)/(x2-x1) as m_slope,
y1-((y2-y1)/(x2-x1))*x1 as y_intercept
from
(
select
cond_id,
road_id,
cond_date - to_date('1980-01-01', 'YYYY-MM-DD') as x1,
condition as y1,
lead(cond_date - to_date('1980-01-01', 'YYYY-MM-DD')) over (partition by road_id order by cond_date) as x2,
lead(condition,1,condition) over (partition by road_id order by cond_date) as y2
from
road_condition
)
)
select distinct
a.road_id,
case when m_slope <> 0 then ((b.numbers - y_intercept)/m_slope) + to_date('1980-01-01', 'YYYY-MM-DD') else a.x1 + to_date('1980-01-01', 'YYYY-MM-DD') end as cond_date,
case when b.numbers between 15 and 20 then b.numbers end as cond_good,
case when b.numbers between 11 and 15 then b.numbers end as cond_overlay,
case when b.numbers between 8 and 11 then b.numbers end as cond_fdr,
case when b.numbers between 0 and 8 then b.numbers end as cond_recon
from
a
cross join
numbers_condition b
where
b.numbers between a.y1 and a.y2
or b.numbers between a.y2 and a.y1
order by
road_id,
cond_date
;
Run Code Online (Sandbox Code Playgroud)
注意:我无法弄清楚如何设置子句where
以仅从交叉连接中获取我想要的记录(一些垃圾/重复记录输出到结果集)。当存在没有斜率或具有正斜率的线段时,情况会变得有点复杂。所以我采取了简单的方法,只是通过 消除了重复项selecting distinct
。
ROAD_ID COND_DAT COND_GOOD COND_OVERLAY COND_FDR COND_RECON
---------- -------- ---------- ------------ ---------- ----------
100 84-11-01 18
100 86-11-06 17
100 88-11-11 16
100 90-11-16 15 15
100 92-11-21 14
100 94-11-26 13
100 96-12-01 12
100 98-12-07 11 11
100 00-12-11 10
100 02-12-17 9
100 04-12-21 8 8
100 06-12-27 7
100 09-01-01 6
100 10-09-25 5
100 12-06-19 4
100 15-04-29 4
200 92-04-29 20
200 93-10-16 19
200 95-04-05 18
200 96-09-22 17
200 98-03-11 16
200 99-08-29 15 15
200 01-02-15 14
200 02-08-04 13
200 04-01-22 12
200 05-07-11 11 11
200 06-12-29 10
200 08-06-16 9
200 09-12-04 8 8
200 11-05-24 7
200 12-11-09 6
200 14-04-29 5
200 15-10-17 4
200 17-04-05 3
Run Code Online (Sandbox Code Playgroud)
受到这个问题的其他答案和我之前的问题的启发:Cross join on a numeric table to get line vertices,是否有更好的方法?
归档时间: |
|
查看次数: |
783 次 |
最近记录: |