2013-12-17 32 views
2

我有一张表,如下所示。Oracle:重复组中的最小最大值

DATE_WORKED COUNTRY 
1-Nov-13 United Kingdom 
4-Nov-13 United Kingdom 
5-Nov-13 India 
6-Nov-13 India 
7-Nov-13 India 
8-Nov-13 United Kingdom 
11-Nov-13 United Kingdom 
12-Nov-13 India 
13-Nov-13 India 
14-Nov-13 India 
15-Nov-13 United Kingdom 
18-Nov-13 United Kingdom 
19-Nov-13 India 
20-Nov-13 India 
21-Nov-13 India 
22-Nov-13 United Kingdom 
25-Nov-13 United Kingdom 
26-Nov-13 India 
27-Nov-13 India 
28-Nov-13 India 
29-Nov-13 United Kingdom 

我在寻找每个逗留在一个国家的start_date和结束日期。

COUNTRY  START_DATE END_Date 
United Kingdom  1-Nov-13 4-Nov-13 
India    5-Nov-13 7-Nov-13 
United Kingdom  8-Nov-13 11-Nov-13 
India    12-Nov-13 14-Nov-13 
United Kingdom  15-Nov-13 18-Nov-13 
India    19-Nov-13 21-Nov-13 
United Kingdom  22-Nov-13 25-Nov-13 
India    26-Nov-13 28-Nov-13 
United Kingdom  29-Nov-13 

请帮我用SQL查询来实现这一点。 在此先感谢。

回答

6

使用Tabibitosan

SQL> create table mytable (date_worked,country) 
    2 as 
    3 select to_date('1-Nov-13','dd-Mon-yy'), 'United Kingdom' from dual union all 
    4 select to_date('4-Nov-13','dd-Mon-yy'), 'United Kingdom' from dual union all 
    5 select to_date('5-Nov-13','dd-Mon-yy'), 'India' from dual union all 
    6 select to_date('6-Nov-13','dd-Mon-yy'), 'India' from dual union all 
    7 select to_date('7-Nov-13','dd-Mon-yy'), 'India' from dual union all 
    8 select to_date('8-Nov-13','dd-Mon-yy'), 'United Kingdom' from dual union all 
    9 select to_date('11-Nov-13','dd-Mon-yy'), 'United Kingdom' from dual union all 
10 select to_date('12-Nov-13','dd-Mon-yy'), 'India' from dual union all 
11 select to_date('13-Nov-13','dd-Mon-yy'), 'India' from dual union all 
12 select to_date('14-Nov-13','dd-Mon-yy'), 'India' from dual union all 
13 select to_date('15-Nov-13','dd-Mon-yy'), 'United Kingdom' from dual union all 
14 select to_date('18-Nov-13','dd-Mon-yy'), 'United Kingdom' from dual union all 
15 select to_date('19-Nov-13','dd-Mon-yy'), 'India' from dual union all 
16 select to_date('20-Nov-13','dd-Mon-yy'), 'India' from dual union all 
17 select to_date('21-Nov-13','dd-Mon-yy'), 'India' from dual union all 
18 select to_date('22-Nov-13','dd-Mon-yy'), 'United Kingdom' from dual union all 
19 select to_date('25-Nov-13','dd-Mon-yy'), 'United Kingdom' from dual union all 
20 select to_date('26-Nov-13','dd-Mon-yy'), 'India' from dual union all 
21 select to_date('27-Nov-13','dd-Mon-yy'), 'India' from dual union all 
22 select to_date('28-Nov-13','dd-Mon-yy'), 'India' from dual union all 
23 select to_date('29-Nov-13','dd-Mon-yy'), 'United Kingdom' from dual 
24/

Table created. 

SQL> with tabibitosan as 
    2 (select row_number() over (order by date_worked) 
    3   - row_number() over (partition by country order by date_worked) grp 
    4   , date_worked 
    5   , country 
    6  from mytable 
    7 ) 
    8 select country 
    9  , min(date_worked) start_date 
10  , max(date_worked) end_date 
11 from tabibitosan 
12 group by country 
13  , grp 
14 order by start_date 
15/

COUNTRY  START_DATE   END_DATE 
-------------- ------------------- ------------------- 
United Kingdom 01-11-2013 00:00:00 04-11-2013 00:00:00 
India   05-11-2013 00:00:00 07-11-2013 00:00:00 
United Kingdom 08-11-2013 00:00:00 11-11-2013 00:00:00 
India   12-11-2013 00:00:00 14-11-2013 00:00:00 
United Kingdom 15-11-2013 00:00:00 18-11-2013 00:00:00 
India   19-11-2013 00:00:00 21-11-2013 00:00:00 
United Kingdom 22-11-2013 00:00:00 25-11-2013 00:00:00 
India   26-11-2013 00:00:00 28-11-2013 00:00:00 
United Kingdom 29-11-2013 00:00:00 29-11-2013 00:00:00 

9 rows selected. 
+0

清洁..高兴,我也想出了相同办法! –

+0

多数民众赞成真棒。我认为这是有效的。今天学习了一项新技术。非常感谢Rob –

0

有点复杂得多@ RobVanWijk的回答是:

with v_data as (
    select to_date('2013-11-01', 'YYYY-MM-DD') as date_worked, 'UK' as country from dual union all 
    select to_date('2013-11-04', 'YYYY-MM-DD') as date_worked, 'UK' as country from dual union all 
    select to_date('2013-11-05', 'YYYY-MM-DD') as date_worked, 'India' as country from dual union all 
    select to_date('2013-11-06', 'YYYY-MM-DD') as date_worked, 'India' as country from dual union all 
    select to_date('2013-11-07', 'YYYY-MM-DD') as date_worked, 'India' as country from dual union all 
    select to_date('2013-11-08', 'YYYY-MM-DD') as date_worked, 'UK' as country from dual union all 
    select to_date('2013-11-11', 'YYYY-MM-DD') as date_worked, 'UK' as country from dual union all 
    select to_date('2013-11-12', 'YYYY-MM-DD') as date_worked, 'India' as country from dual 
) 
select country, start_day, end_day from (
    select 
    v3.*, 
    row_number() over (partition by start_day, end_day order by date_worked) as rn 
    from ( 
    select 
     v2.*, 
     max(case when is_first_day = 1 then date_worked else null end) over (Partition by null order by date_worked) as start_day, 
     min(case when is_last_day = 1 then date_worked else null end) over (Partition by null order by date_worked desc) as end_day 
    from ( 
     select 
     v1.*, 
     (case when country <> nvl(country_next_day, 'n/a') then 1 else 0 end) is_last_day, 
     (case when country <> nvl(country_prev_day, 'n/a') then 1 else 0 end) is_first_day 
     from ( 
     select 
      date_worked, 
      country, 
      lead(country) over (order by date_worked) as country_next_day, 
      lag(country) over (order by date_worked) as country_prev_day 
     from v_data 
    ) v1 
    ) v2 
    order by date_worked 
) v3 
) v4 where rn=1 

说明:

  • 每个工作日,让继任者,并使用滞后的前身()和lead()分析函数(v1)
  • 每个工作日,确定它是否是一个组的开始或结束其国家比较以前的和未来的国家(V2)
  • 每个组,计算开始和结束日(V3)
  • 为每个工作日,计算其组内的排序(V4)
  • 回报仅限订购1
0

尝试此查询工作日:

select country,min(date_worked) as start_date,max(date_worked) as end_date 
from (select country,date_worked, 
    Row_Number() over(order by date_worked) 
    -Row_Number() over(partition by country order by date_worked) as disTance 
    from YourTable) 
group by disTance,country order by min(date_worked);