2013-03-26 58 views
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 |    | 
+---------------+--------+-----------+--------+-------------+ 
+0

至于代码,我需要它给我的每一个特定状态的开始和结束日期为每个区域,即多长时间做最后在区域A冻结?我已经尝试了子查询,这些子查询为每个状态提供了最早的日期,但无法正确地将它们与正确的状态更改进行配对。类似于LEAD的功能将是理想的,但比下一个记录更具有延伸性。 – David 2013-03-26 21:53:12

+0

冰/水/气是不是真实的数据,我的问题只是代表......真正的查询是漫长的,肯定会浪费你的时间。很简单,选择四列来自四个不同的表格,其中“更改日期”是我无法创建的列。如果这还不够,更多道歉,这是新的,不想浪费你的时间。 – David 2013-03-26 22:00:11

+0

@大卫:很多SQL问题在这里倾向于使用SQL小提琴,以显示你的架构设置,到目前为止,你已经尝试过的东西;这里有一个开始的地方:http://sqlfiddle.com/#!4/7e66a/2你可以添加一个样本查询你到目前为止已经尝试过吗? – Alkini 2013-03-26 22:14:28

回答

1

模式条款(10克+)可在非常紧凑的方式做到这一点:

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)] 

它说,我们的三个维度,只能看着与同一区域(cv(Region),)行和看行,其中该日期跟随当前行的日期(obs_date > cv(obs_date)),并且状态不同于当前行(status != cv(status)),最后获得满足此组条件的最小日期(min(obs_date2))并将其分配给status_change。左边的any,any,any部分表示此计算适用于所有行。

+0

Dazzal,我第一次尝试这种做法,它像魅力一样工作。在将它适配到真实数据后,只需添加一个唯一的单一引用即可。我已经迈出了建模的第一步! – David 2013-04-01 20:33:49

+0

很多人很感谢,会发现如何给你适当的网站荣誉。 – David 2013-04-01 20:34:25

+0

@大卫,你只需选中的答案,如果它可以解决你的问题 – DazzaL 2013-04-02 20:59:20

0

我经常在清理从/到日期和重复行的重叠时执行此操作。 你的情况要简单得多,不过,因为你只有“从最新的” :)

建立测试数据

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; 

下面的查询有兴趣三点:

  1. 识别重复的信息(记录显示相同先前记录)
  2. 忽略重复录音
  3. 确定DAT e从“下一个”变更

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

Ronnis,非常感谢,将尝试了这一点,让大家都知道下周 – David 2013-03-27 13:16:16

1

我试过很多次,了解MODEL子句,从来没有真的挺管理它,所以以为我想补充另一种解决方案

这种解决方案需要一些什么Ronnis做,而是使用的的IGNORE NULLS条款LEAD功能。我认为这只是Oracle 11的新功能,如果有必要,您可以用Oracle 10的FIRST_VALUE函数替换它。

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

多少条条大道通罗马?迈克非常有责任,下星期给我结果 – David 2013-03-27 13:17:00

相关问题