我有一个非常简单的表格:
CREATE TABLE T_ACTIVITY_LOG
(
ACTIVITY_DATE TIMESTAMP,
APPLIANCE_ID NUMBER(9) DEFAULT 0 NOT NULL,
APPLIANCE_STATUS NUMBER(1) DEFAULT 0 NOT NULL
)
记录各种工业设备的状态变化(-1和0)。每次修改状态时,都会在表中插入记录:
APPLIANCE_ID ACTIVITY_DATE APPLIANCE_STATUS
---------- ------------------- -----------
1 01-jan-15 00:00:00 0
1 11-jan-15 00:00:00 1
1 21-jan-15 00:00:00 0
1 30-jan-15 00:00:00 1
现在我正在处理报告,我需要生成一个数据集,其中包含每月中每天的行以及相应的设备状态:
APPLIANCE_ID ACTIVITY_DATE APPLIANCE_STATUS
---------- ------------------- -----------
1 01-jan-15 00:00:00 0
1 02-jan-15 00:00:00 0
1 03-jan-15 00:00:00 0
1 04-jan-15 00:00:00 0
1 05-jan-15 00:00:00 0
1 06-jan-15 00:00:00 0
1 07-jan-15 00:00:00 0
1 08-jan-15 00:00:00 0
1 09-jan-15 00:00:00 0
1 10-jan-15 00:00:00 0
1 11-jan-15 00:00:00 1
1 12-jan-15 00:00:00 1
1 13-jan-15 00:00:00 1
1 14-jan-15 00:00:00 1
1 15-jan-15 00:00:00 1
1 16-jan-15 00:00:00 1
1 17-jan-15 00:00:00 1
1 18-jan-15 00:00:00 1
1 19-jan-15 00:00:00 1
1 20-jan-15 00:00:00 1
1 21-jan-15 00:00:00 0
1 22-jan-15 00:00:00 0
1 23-jan-15 00:00:00 0
1 24-jan-15 00:00:00 0
1 25-jan-15 00:00:00 0
1 26-jan-15 00:00:00 0
1 27-jan-15 00:00:00 0
1 28-jan-15 00:00:00 0
1 29-jan-15 00:00:00 0
1 30-jan-15 00:00:00 1
1 31-jan-15 00:00:00 1
是否可以通过SQL执行此操作,或者我是否应该使用软件中的临时表来自行构建数据集?
谢谢!
答案 0 :(得分:4)
Oracle支持分区外连接语法,允许在行不可用的地方填充稀疏数据,并且在this tutorial中,还有一种方法可以填充具有最新值的空白。
答案 1 :(得分:1)
为了实现您的目标,需要三种技术:
如:
with t_activity_log as (select 1 appliance_id, to_date('01/01/2015', 'dd/mm/yyyy') activity_date, 0 appliance_status from dual union all
select 1 appliance_id, to_date('11/01/2015', 'dd/mm/yyyy') activity_date, 1 appliance_status from dual union all
select 1 appliance_id, to_date('21/01/2015', 'dd/mm/yyyy') activity_date, 0 appliance_status from dual union all
select 1 appliance_id, to_date('30/01/2015', 'dd/mm/yyyy') activity_date, 1 appliance_status from dual union all
select 2 appliance_id, to_date('02/01/2015', 'dd/mm/yyyy') activity_date, 0 appliance_status from dual union all
select 2 appliance_id, to_date('10/01/2015', 'dd/mm/yyyy') activity_date, 1 appliance_status from dual union all
select 2 appliance_id, to_date('15/01/2015', 'dd/mm/yyyy') activity_date, 0 appliance_status from dual union all
select 2 appliance_id, to_date('26/01/2015', 'dd/mm/yyyy') activity_date, 1 appliance_status from dual),
dates as (select to_date('01/01/2015', 'dd/mm/yyyy') -1 + level dt
from dual
connect by level <= 31) -- query to generate the list of dates; amend as appropriate to get the list of dates you're after
select tal.appliance_id,
dts.dt,
last_value(tal.appliance_status ignore nulls) over (partition by tal.appliance_id order by dts.dt) appliance_status
from dates dts
left outer join t_activity_log tal partition by (tal.appliance_id) on (dts.dt = tal.activity_date)
order by tal.appliance_id,
dts.dt;
APPLIANCE_ID DT APPLIANCE_STATUS
------------ ---------- ----------------
1 01/01/2015 0
1 02/01/2015 0
1 03/01/2015 0
1 04/01/2015 0
1 05/01/2015 0
1 06/01/2015 0
1 07/01/2015 0
1 08/01/2015 0
1 09/01/2015 0
1 10/01/2015 0
1 11/01/2015 1
1 12/01/2015 1
1 13/01/2015 1
1 14/01/2015 1
1 15/01/2015 1
1 16/01/2015 1
1 17/01/2015 1
1 18/01/2015 1
1 19/01/2015 1
1 20/01/2015 1
1 21/01/2015 0
1 22/01/2015 0
1 23/01/2015 0
1 24/01/2015 0
1 25/01/2015 0
1 26/01/2015 0
1 27/01/2015 0
1 28/01/2015 0
1 29/01/2015 0
1 30/01/2015 1
1 31/01/2015 1
2 01/01/2015
2 02/01/2015 0
2 03/01/2015 0
2 04/01/2015 0
2 05/01/2015 0
2 06/01/2015 0
2 07/01/2015 0
2 08/01/2015 0
2 09/01/2015 0
2 10/01/2015 1
2 11/01/2015 1
2 12/01/2015 1
2 13/01/2015 1
2 14/01/2015 1
2 15/01/2015 0
2 16/01/2015 0
2 17/01/2015 0
2 18/01/2015 0
2 19/01/2015 0
2 20/01/2015 0
2 21/01/2015 0
2 22/01/2015 0
2 23/01/2015 0
2 24/01/2015 0
2 25/01/2015 0
2 26/01/2015 1
2 27/01/2015 1
2 28/01/2015 1
2 29/01/2015 1
2 30/01/2015 1
2 31/01/2015 1
NB。你不会说如果第一个appliance_date在日期开始之后会发生什么(参见2月1日的appliance_id = 2),所以我把它默认为null。如果您不希望显示这些行,则必须围绕上述SQL抛出外部查询以过滤appliance_status不为空。
如果您希望它不同(例如,在指定的开始日期和结束日期之间,或者基于表格数据等),您还必须修改生成日期的查询。关于如何生成日期列表的例子很多。