2

最後の列を除いて、次を返すクエリがあります。これは、作成方法を理解するために必要なものです。与えられたそれぞれについてObservationID、ステータスが変更された日付を返す必要があります。オフセットだけでなく条件を受け取るLEAD()関数のようなもの。できますか?

列変更日を計算する必要があります。ステータスが現在のステータスではなかった最後の日付である必要があります。

+---------------+--------+-----------+--------+-------------+
| ObservationID | Region |   Date    | Status | Change Date | <-This field
+---------------+--------+-----------+--------+-------------+
|             1 |     10 | 1/3/2012  | Ice    | 1/4/2012    |
|             2 |     10 | 1/4/2012  | Water  | 1/6/2012    |
|             3 |     10 | 1/5/2012  | Water  | 1/6/2012    |
|             4 |     10 | 1/6/2012  | Gas    | 1/7/2012    |
|             5 |     10 | 1/7/2012  | Ice    |             |
|             6 |     20 | 2/6/2012  | Water  | 2/10/2012   |
|             7 |     20 | 2/7/2012  | Water  | 2/10/2012   |
|             8 |     20 | 2/8/2012  | Water  | 2/10/2012   |
|             9 |     20 | 2/9/2012  | Water  | 2/10/2012   |
|            10 |     20 | 2/10/2012 | Ice    |             |
+---------------+--------+-----------+--------+-------------+
4

3 に答える 3

1

モデル句(10g +)は、これをコンパクトな方法で実行できます。

SQL> create table observation(ObservationID ,  Region  ,obs_date,  Status)
  2  as
  3  select  1, 10, date '2012-03-01', 'Ice' from dual union all
  4  select  2, 10, date '2012-04-01', 'Water' from dual union all
  5  select  3, 10, date '2012-05-01', 'Water' from dual union all
  6  select  4, 10, date '2012-06-01', 'Gas' from dual union all
  7  select  5, 10, date '2012-07-01', 'Ice' from dual union all
  8  select  6, 20, date '2012-06-02', 'Water' from dual union all
  9  select  7, 20, date '2012-07-02', 'Water' from dual union all
 10  select  8, 20, date '2012-08-02', 'Water' from dual union all
 11  select  9, 20, date '2012-09-02', 'Water' from dual union all
 12  select 10, 20, date '2012-10-02', 'Ice' from dual ;

Table created.

SQL> select ObservationID, obs_date, Status, status_change
  2            from observation
  3          model
  4          dimension by (Region, obs_date, Status)
  5          measures ( ObservationID, obs_date obs_date2, cast(null as date) status_change)
  6          rules (
  7            status_change[any,any,any] = min(obs_date2)[cv(Region), obs_date > cv(obs_date), status != cv(status)]
  8          )
  9   order by 1;

OBSERVATIONID OBS_DATE  STATU STATUS_CH
------------- --------- ----- ---------
            1 01-MAR-12 Ice   01-APR-12
            2 01-APR-12 Water 01-JUN-12
            3 01-MAY-12 Water 01-JUN-12
            4 01-JUN-12 Gas   01-JUL-12
            5 01-JUL-12 Ice
            6 02-JUN-12 Water 02-OCT-12
            7 02-JUL-12 Water 02-OCT-12
            8 02-AUG-12 Water 02-OCT-12
            9 02-SEP-12 Water 02-OCT-12
           10 02-OCT-12 Ice

フィドル:http ://sqlfiddle.com/#!4 / f6687 / 1

つまり、同じ地域のセルを見たいので、地域、日付、ステータスでディメンションを作成しますが、ステータスが異なる最初の日付を取得します。

また、日付も測定する必要があるため、そのためのエイリアスobs_date2を作成しました。新しい列status_changeに、ステータスが変更された日付を保持する必要があります。

この行は、私たちのためにすべての作業を行う行です。

status_change[any,any,any] = min(obs_date2)[cv(Region), obs_date > cv(obs_date), status != cv(status)]

これは、3次元の場合、同じ領域(cv(Region),)を持つ行のみを確認し、日付が現在の行の日付に続く行(obs_date > cv(obs_date))を確認し、ステータスが現在の行()と異なる場合status != cv(status)に最終的に取得することを示しています。この一連の条件()を満たす最小の日付をmin(obs_date2)に割り当てstatus_changeます。any,any,any左側の部分は、この計算がすべての行に適用されることを意味します。

于 2013-03-26T23:24:27.350 に答える
1

私は何度もMODEL句を理解しようとしましたが、実際には完全に管理できなかったので、別のソリューションを追加しようと思いました

このソリューションは、Ronnisが行ったことの一部を取りますが、代わりIGNORE NULLSにLEAD関数の句を使用します。これはOracle11でのみ新しいことだと思いますがFIRST_VALUE、必要に応じてOracle10の関数に置き換えることができます。

select
  observation_id,
  region,
  observation_date,
  status,
  lead(case when is_change = 'Y' then observation_date end) ignore nulls 
    over (partition by region order by observation_date) as change_observation_date
from (
  select
    a.observation_id,
    a.region,
    a.observation_date,
    a.status,
    case 
      when status = lag(status) over (partition by region order by observation_date) 
        then null
        else 'Y' end as is_change
       from observations a
)
order by 1
于 2013-03-27T07:23:10.750 に答える
0

重複するfrom/to-datesと重複する行をクリーンアップするときにこれを頻繁に行います。ただし、「開始日」しかないため、ケースははるかに単純です:)

テストデータの設定

create table observations(
   observation_id   number       not null
  ,region           number       not null
  ,observation_date date         not null
  ,status           varchar2(10) not null
);


insert 
  into observations(observation_id, region, observation_date, status)
   select 1,  10, date '2012-03-01', 'Ice'   from dual union all
   select 2,  10, date '2012-04-01', 'Water' from dual union all
   select 3,  10, date '2012-05-01', 'Water' from dual union all
   select 4,  10, date '2012-06-01', 'Gas'   from dual union all
   select 5,  10, date '2012-07-01', 'Ice'   from dual union all
   select 6,  20, date '2012-06-02', 'Water' from dual union all
   select 7,  20, date '2012-07-02', 'Water' from dual union all
   select 8,  20, date '2012-08-02', 'Water' from dual union all
   select 9,  20, date '2012-09-02', 'Water' from dual union all
   select 10, 20, date '2012-10-02', 'Ice'   from dual;

commit;

以下のクエリには、3つの重要なポイントがあります。

  1. 繰り返される情報の特定(記録は以前の記録と同じように表示されます)
  2. 繰り返される録音を無視する
  3. 「次の」変更からの日付の決定

with lagged as(
   select a.*
         ,case when status = lag(status, 1) over(partition by region 
                                                     order by observation_date) 
               then null 
               else rownum 
           end as change_flag -- 1
     from observations a
)
select observation_id
      ,region
      ,observation_date
      ,status
      ,lead(observation_date, 1) over(
         partition by region 
             order by observation_date
      ) as change_date --3
      ,lead(observation_date, 1, sysdate) over(
         partition by region 
             order by observation_date
      ) - observation_date as duration
  from lagged
 where change_flag is not null -- 2
 ;
于 2013-03-26T22:55:20.343 に答える