我有一张断电信息表,看起来像这样,
event_ID event_timestamp event_info POWER LINE ID
44 1/5 1:45 pm power on 247
45 1/5 1:45 pm power on 247
46 1/5 3:45 pm fault detected 247
47 1/5 3:55 pm power off 247
48 1/5 3:58 pm power off 247
49 1/5 5:15 pm power on 247
50 1/5 5:45 pm power off 247
51 1/5 5:50 pm power off 247
52 1/5 5:55 pm power off 247
53 1/5 5:59 pm power off 247
KEY只是表格的主键。停电时间告诉我们停电发生的时间,电力线ID只是发生停电的线路的识别号码。
我有第二个包含仪表信息的表,看起来像这样,
KEY event_ID POWER LINE ID
2 46 247
2 47 247
2 48 247
3 50 247
3 51 247
3 52 247
3 53 247
目标如下:对于每次停电,选择在停电时间之前以及最近的电源开启后在该电力线上发生的所有仪表事件。在该电力线上发生的信号。
例如,对于停机#2,我们将在1/5下午4:00(停电时间)之前查看所有仪表事件,但是在1/5 1:45 pm之后发生的所有事件,因为这是最新的"开机"停电前发生的信号。对于停机#3,我们会查看在下午1/5下午6:00(停电时间)之前发生的所有事件,但是在1/5下午5:15之后,因为这是最近的"电源开启&# 34;在停电时间之前发生的信号。
我使用游标循环停止表并调用从事件表中选择所需事件的存储过程,但是这些表非常大,并且光标花费的时间太长。我想知道一种基于集合的方法来解决这个问题。谢谢!
编辑:对不起,我完全忘了发布示例输出。在这里。using MySql.Data.MySqlClient;
using System.Data;
编辑(再次):我正在Oracle中寻找解决方案。我很抱歉编辑,第一次在这里发帖提问。
答案 0 :(得分:1)
我正在使用SQL Server解决问题,因此#
表示临时表。
假设下面的表和数据
create table #outage ([key] int, outage_time datetime, power_line int)
insert into #outage values
(1, '2015/1/1 2:30 pm', 75),
(2, '2015/1/5 4:00 pm', 247),
(3, '2015/1/5 6:00 pm', 247),
(4, '2015/1/3 8:00 am', 11)
create table #even (event_ID int , event_time datetime,
event_info varchar(20), power_line int)
insert into #even values
(44, '2015/1/5 1:45 pm' ,'power on' ,247),
(45, '2015/1/5 1:45 pm' ,'power on' ,247),
(46, '2015/1/5 3:45 pm' ,'fault detected' ,247),
(47, '2015/1/5 3:55 pm' ,'power off' ,247),
(48, '2015/1/5 3:58 pm' ,'power off' ,247),
(49, '2015/1/5 5:15 pm' ,'power on' ,247),
(50, '2015/1/5 5:45 pm' ,'power off' ,247),
(51, '2015/1/5 5:50 pm' ,'power off' ,247),
(52, '2015/1/5 5:55 pm' ,'power off' ,247),
(53, '2015/1/5 5:59 pm' ,'power off' ,247)
这是查询:
select o.[key], e.event_ID, o.power_line
from #outage o
inner join #even e on e.power_line = o.power_line
and e.event_time < o.outage_time
and e.event_time > (select max(event_time) from #even
where power_line = o.power_line
and event_time < o.outage_time
and event_info = 'power on')
答案 1 :(得分:1)
试试这个:
SELECT power_outage.key,
meters.event_id,
power_outage.power_line_id
FROM power_outage
JOIN meter_info meters
ON power_outage.power_line_id = meters.power_line_id
AND meters.event_timestamp < power_outage.outage_time
WHERE meters.event_timestamp > (SELECT MAX(lpo.event_timestamp)
FROM meter_info lpo -- LastPowerOn
WHERE lpo.power_line_id = power_outage.power_line_id
AND lpo.event_info = 'power on'
AND lpo.event_timestamp < power_outage.outage_time);
“JOIN”会在中断时间之前获取所有元素,而条件会过滤与最近一次上电相对应的元素。
答案 2 :(得分:1)
这是一个涉及CTE
的较长查询,但逐步更容易理解:
WITH events_before_outage AS (
select
ot.key, ot.outage_time, ot.power_line_id, mi.event_id, mi.event_timestamp, mi.event_info
from outage_table ot
left join meter_information mi
on ot.power_line_id = mi.power_line_id
and ot.outage_time > mi.event_timestamp
)
, last_power_on AS (
select key, max(event_timestamp) as event_date
from events_before_outage
where event_info = 'power on'
group by 1
)
select a.key, a.event_id, a.power_line_id
from events_before_outage a
where a.event_timestamp > ( select event_date from last_power_on b where a.key = b.key )
order by 1,2
输出:
key | event_id | power_line_id
-----+----------+---------------
2 | 46 | 247
2 | 47 | 247
2 | 48 | 247
3 | 50 | 247
3 | 51 | 247
3 | 52 | 247
3 | 53 | 247
答案 3 :(得分:0)
这是一种使用分析函数的完全基于集合的方法。这个想法是通过对它们进行累积计数来枚举“poweron”来获得组。然后,使用此组获取组中任何断电的时间,并返回值。
select om.*
from (select om.*,
max(om.outagetime) over (partition by poweron_grp, powerlineid) as outagetime,
min(event_timestamp) over (partition by powerongrp, powerlineid as minet,
max(event_timestamp) over (partition by powerongrp, powerlineid as maxet
from (select m.*, o.outagetime,
sum(case when m.event_info = 'power on' then 1 else 0 end) over
(partition by m.powerlineid order by m.event_timestamp
) as poweron_grp
from outages o join
meters m
on o.powerlineid = m.powerlineid
) om
) om
where outagetime between minte and maxte and
event_timestamp < outagetime;
答案 4 :(得分:0)
一些建议的答案使用完整的仪表信息表使用相关的子查询,即使它们只需要event_info ='power on'的行。对每个连续的行计算相关的子查询,因此所有这些不需要的行都会被评估 - 并被丢弃 - 多次。因此,如果有很多事件的event_info与'power on'不同,这似乎就是这种情况,那么只需隔离'开机'事件就可以实现额外的效率。
这是一种方法。我给表格命名为outage_data和meter_data,在outage_data表中我将“key”列命名为outage_ID;使用关键字作为列名是一个非常糟糕的主意,而key ...是...一个关键字!子查询(cte)p被评估一次,它只是使用event_info ='power on'收集事件,相关子查询是针对p的,而不是针对完整的meter_data表。
with p as (select power_line, event_time from meter_data where event_info = 'power on')
select o.outage_ID, m.event_ID, o.power_line
from outage_data o join meter_data m on m.power_line = o.power_line
where m.event_time <= o.outage_time
and m.event_time > (select max(p.event_time) from p
where p.power_line = o.power_line and p.event_time <= o.outage_time)
order by o.outage_ID, m.event_ID