2016-04-01 4 views
2

の各行をループIはセットベースのソリューションを見つける代わりに、SQL

KEY  OUTAGE TIME  POWER LINE ID 
1  1/1 2:30 pm  75 
2  1/5 4:00 pm  247 
3  1/5 6:00 pm  247 
4  1/3 8:00 am  11 

KEYは、ちょうどテーブルの主キーであり、このようになり、停電情報を持つテーブルを持っています。停電時間は、停電が発生したときにわかり、電力線IDは停電が発生した回線の識別番号にすぎません。私はこのようになりますメーター情報、を有する第二のテーブルを持っている

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 

目標は次のとおりです。各停電のため、停止時間前に電源ラインに起こった全てのメーターのイベントを選択しますその電源ライン上で発生した最新の「パワーオン」信号の後に、

たとえば、停電2の場合、1/5午後4時(停止時間)前にすべてのメーターイベントを確認しますが、これ以降1/5午後1時45分以降に発生したすべてのイベント停止前に発生した最新の「パワーオン」信号です。停電3の場合、1/5午後6時(停止時間)前に発生したすべてのイベントを調べますが、これは発生した最新の「電源投入」信号であるため1/5午後5時15分頃以降です停止時間の前に。

私は、停止テーブルをループし、イベントテーブルから目的のイベントを選択するストアドプロシージャを呼び出すカーソルでこれを行っていますが、これらのテーブルは非常に大きく、カーソルが長すぎます。私は、この問題にアプローチするセットベースの方法を知りたいと思います。ありがとう!

EDIT:申し訳ありませんが、サンプル出力を投稿するのを完全に忘れました。ここにあります。

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 

EDIT(再び):私はOracleでこれに対する解決策を探しています。私は編集のために申し訳ありません、初めてここに質問を投稿します。

+0

曖昧なDBMSタグが削除され、適切なものを含むように編集が保留されました。さまざまなデータベースシステムに固有の回答があります。 –

+0

私はこの質問を理解していますか?あなたのテーブル内の ''停止 '行ごとに、停電タイムスタンプと最大の "パワーオン"タイムスタンプの間にタイムスタンプがあるものを除いて、すべての 'イベント'行**を選択しますか?もう1つの質問: 'OUTAGE TIME'と' event_timestamp'カラムのあなたのテーブルのデータ型は何ですか? –

+1

@jpwサンプル出力を追加しました – user6147110

答えて

2

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 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のは' 限り、彼らが発生したとして、すべての要素を取得します:

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') 
+0

ああ、私はあなたがそれをやったのを見て、最初に加入して停電IDを電力線IDに基づいてイベントにペア設定し、その基準に基づいて必要なイベントを選択します。カーソルよりもはるかに高速ですので、お手数ではありがとうございます! – user6147110

1

はこれを試してみてください停電時間の前に、最新の電源投入に対応する要素をフィルタリングします。

+0

私の答えは、私がやって来る直前に投稿されたフリッカーと多かれ少なかれ同等であることに気付きました。私はその答えが私のことを投稿した後にしか見ませんでした。 –

+0

援助ありがとう、私は大いに感謝します! – user6147110

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 
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; 
0

提案の答えのいくつかは、彼らが唯一のEVENT_INFO =「電源オン」の行をNEEDにもかかわらず、完全なメーター情報のテーブルを使用して相関サブクエリを使用します。相関サブクエリは連続する行ごとに評価されるので、不要な行は何度も評価され、破棄されます。したがって、 'power on'とは異なるevent_infoを持つイベントが多数ある場合は、 'power on'イベントだけを分離することで効率を上げることができます。

これを行う方法が1つあります。私はテーブルにoutage_dataとmeter_dataという名前を付け、outage_dataテーブルでは "key"カラムにoutage_IDという名前を付けました。列名としてキーワードを使用することは本当に悪い考えであり、キーは...キーワードです!サブクエリ(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 
関連する問題