0

次のようなデータを含むログ テーブルがあります。

ID MSG 日付
----------------------------------------------
1 テスト 2010-01-01 09:00:00
2 ジョブ開始 2010-01-01 09:03:00
3 何とかしろ 2010-01-01 09:03:10
4 別のことをする 2010-01-01 09:03:12
5 何とかしろ 2010-01-01 09:04:19
6 ジョブ終了 2010-01-01 09:06:30
7 ジョブ開始 2010-01-01 09:18:03
8 何とかしろ 2010-01-01 09:18:17
9 他のことをする 2010-01-01 09:19:48
10 ジョブ終了 2010-01-01 09:20:27

これには、(とりわけ) アプリケーションによって書き込まれたメッセージが含まれます。このような「ジョブ開始」と「ジョブ終了」のすべてのペアについて、「ジョブ開始」レコードと「ジョブ終了」レコードの間に書き込まれるすべてのレポートを作成することに関心があります。理想的には、レポートは次のようになります。

BATCH_NUM ID MSG 日付
-------------------------------------------------- -------         
1 3 何とかしろ 2010-01-01 09:03:10
1 4 別のことをする 2010-01-01 09:03:12
1 5 何とかしろ 2010-01-01 09:04:19

2 8 何とかしろ 2010-01-01 09:18:17
2 9 他のことをする 2010-01-01 09:19:48

(読みやすくするためにバッチ間に改行を追加)

出力レポートでは、「Job STart」メッセージと「Job End」メッセージ、および「TEst」メッセージ (「Job Start」と「Job End」のペアの外に存在するメッセージ) が省略されます。

この種のクエリをどこから書き始めればよいのか、あるいは PL/SQL を使用する方がよいのかどうかさえわかりません。一体、私がやろうとしていることに対して適切な技術用語があるかどうかさえわかりません。;)

(オラクル版は10g)

4

3 に答える 3

1

これを行うためのより分析的な方法があると確信していますが、ウィンドウを構築するためにスカラーサブクエリをごまかしています。

SQL> select * from logging_table;

        ID MSG                            LOG_DT
---------- ------------------------------ -------------------
         1 TEst                           2010-01-01 09:00:00
         2 Job Start                      2010-01-01 09:03:00
         3 Do something                   2010-01-01 09:03:10
         4 Do something else              2010-01-01 09:03:12
         5 Do something                   2010-01-01 09:04:19
         6 Job End                        2010-01-01 09:06:30
         7 Job Start                      2010-01-01 09:18:03
         8 Do something                   2010-01-01 09:18:17
         9 Do other thing                 2010-01-01 09:19:48
        10 Job End                        2010-01-01 09:20:27

SQL> l
  1      select dense_rank() over (order by job_start_id) as batch, 
         -- ^-- this part gets the batch
  2             job_step_id, msg, log_dt
  3             -- nested select to filter out rows outside of the boundaries
  4        from (select *
  5                from (select id as job_step_id, msg, log_dt,
  6                             -- scalar subquery to get start of "window"
  7                             (select max(id)
  8                                from logging_table
  9                               where msg = 'Job Start'
 10                                 and id < log.id) as job_start_id,
 11                             -- scalar subquery to get end of "window"
 12                             (select min(id)
 13                                from logging_table
 14                               where msg = 'Job End'
 15                                 and id > log.id) as job_end_id
 16                       from logging_table log
 17                      -- filter out the "window" rows themselves
 18                      where msg not in ('Job Start', 'Job End')
 19                     )
 20               -- the filtering out of "unbounded" records
 21               where job_start_id is not null
 22                 and job_end_id is not null
 23             )
 24*      order by job_step_id
SQL> /

 BATCH JOB_STEP_ID MSG                            LOG_DT

     1           3 Do something                   2010-01-01 09:03:10
     1           4 Do something else              2010-01-01 09:03:12
     1           5 Do something                   2010-01-01 09:04:19
     2           8 Do something                   2010-01-01 09:18:17
     2           9 Do other thing                 2010-01-01 09:19:48
于 2010-03-03T20:24:29.130 に答える
0

念のため、ウィンドウ関数を使用せずに同じトリックを行う方法を次に示します。

with logging_table as (
    select 1 id, 'job start' msg from dual union
    select 2, 'do somenthing in batch 1' from dual union
    select 3, 'do somenthing else in batch 1' from dual union
    select 4, 'job end' from dual union
    select 5, 'job start' from dual union
    select 6, 'do somenthing in batch 2' from dual union
    select 7, 'do somenthing else in batch 2' from dual union    
    select 8, 'job end' from dual 
),
jobs as (
    select  lt_start.id id_start,
           (select min(id) 
            from logging_table lt_end 
            where lt_end.id > lt_start.id 
            and msg = 'job end') id_end,
            rownum as batch_no
    from    logging_table lt_start
    where   msg = 'job start'
)
select  *
from    logging_table join jobs 
        on id > id_start and id < id_end
order   by batch_no, id    
于 2016-03-09T14:24:56.567 に答える
0

次のサンプルでは、​​Adam Musch の回答とほぼ同じ考え方を使用していますが、スカラー サブクエリを使用するのではなく、ロギング ステートメントに結合された単一の選択でロギング セットの開始と終了を取得します。

パーティションに使用できる列がないため、DENSE_RANK() をこれ以上直接使用することはできないと思います。

また、これらのソリューションのいずれも、ログのセットが重複しないことを前提としています。最初のセットが終了する前に 2 番目のセットが開始された場合、それはまったく新しい問題です...

WITH logging_sets AS
     (SELECT DENSE_RANK () OVER (ORDER BY start_date) AS set_rank, start_date, end_date
        FROM (SELECT CASE msg
                        WHEN 'Job End'
                           THEN NULL
                        ELSE LEAD (log_dt, 1, NULL) OVER (ORDER BY log_dt)
                     END AS end_date, log_dt AS start_date, msg
                FROM logging_table lt
               WHERE msg IN ('Job Start', 'Job End') )
       WHERE msg = 'Job Start')
SELECT ls.set_rank, lt.ID, lt.msg, lt.log_dt
  FROM logging_table lt, logging_sets ls
 WHERE lt.log_dt > ls.start_date AND lt.log_dt < ls.end_date 
   AND msg NOT IN ('Job Start', 'Job End')
ORDER BY ls.set_rank, lt.log_dt;
于 2010-03-05T17:23:37.533 に答える