Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/79.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何根据Oracle中两列值的差异合并/分组记录_Sql_Oracle_Merge_Group By - Fatal编程技术网

Sql 如何根据Oracle中两列值的差异合并/分组记录

Sql 如何根据Oracle中两列值的差异合并/分组记录,sql,oracle,merge,group-by,Sql,Oracle,Merge,Group By,我有以下数据集 from to stayed 01.01.2011 03.04.2011 NY 03.04.2011 25.05.2011 NJ 25.05.2011 04.06.2011 NJ 04.06.2011 20.06.2011 NJ 20.06.2011 30.06.2011 NJ 30.06.2011 05.07.2011 CA 05.07.2011

我有以下数据集

from            to           stayed
01.01.2011     03.04.2011    NY
03.04.2011     25.05.2011    NJ
25.05.2011     04.06.2011    NJ
04.06.2011     20.06.2011    NJ
20.06.2011     30.06.2011    NJ
30.06.2011     05.07.2011    CA
05.07.2011     20.07.2011    CA
20.07.2011     05.08.2011    NY
必须转换成这样

from            to          stayed
01.01.2011     03.04.2011    NY
03.04.2011     30.06.2011    NJ
30.06.2011     20.07.2011    CA
20.07.2011     05.08.2011    NY
另一个数据集与前一个“到”和当前的“从”之间存在差距,应将其计算为新行,如下所示

from            to           stayed
01.01.2011     03.04.2011    NY
03.04.2011     25.05.2011    NJ
25.05.2011     04.06.2011    NJ
04.06.2011     20.06.2011    NJ
20.06.2011     30.06.2011    NJ
30.06.2011     05.07.2011    CA
05.07.2011     20.07.2011    CA
20.07.2011     05.08.2011    NY
16.09.2011     20.09.2011    NY
20.09.2011     29.09.2011    NY
05.10.2011     20.10.2011    NY
from to stayed 01.01.2011 03.04.2011 NY 03.04.2011 30.06.2011 NJ 30.06.2011 20.07.2011 CA 20.07.2011 05.08.2011 NY 16.09.2011 29.09.2011 NY 05.10.2011 20.10.2011 NY 预期结果如下:, from to stayed 01.01.2011 03.04.2011 NY 03.04.2011 30.06.2011 NJ 30.06.2011 20.07.2011 CA 20.07.2011 05.08.2011 NY 16.09.2011 29.09.2011 NY 05.10.2011 20.10.2011 NY 从头到尾 2011年1月1日2011年4月3日纽约 2011年4月3日2011年6月30日新泽西州 2011年6月30日加利福尼亚州2011年7月20日 20.07.2011 05.08.2011纽约 2011年9月16日2011年9月29日纽约 2011年10月5日2011年10月20日纽约

为了进行这种合并,我编写了带有分析函数的复杂查询。有没有一个简单的方法可以做到这一点

Select distinct 
   min(from) over (parttion by stayed order by from) as from_stayed,
   max(to) over (parttion by stayed order by to) as to_stayed,
   stayed
from table
好的,试试这个

with t2 as
(select t1.*,
  case lag(stayed,1,stayed) over (order by dt)
  when stayed then 0 else 1 end as stayed_mod
from table),
t3 as 
  (select t2.*,
    sum(stayed_mod) over (order by from) as group_id
  from t2)
select distinct stayed,
  min(from) over (partition by GROUP_ID) as from_min,
  max(to) over (partition by GROUP_ID) as to_max
from t3
order by 2;

Oracle 11g R2架构设置

CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH groups AS (
  SELECT t.*,
         ROW_NUMBER() OVER ( ORDER BY "from" ) - ROW_NUMBER() OVER ( PARTITION BY "stayed" ORDER BY "from" ) AS grp
  FROM   tbl t
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       "stayed"
FROM   groups
GROUP BY "stayed", grp
ORDER BY "from"
|                           FROM |                            TO | STAYED |
|--------------------------------|-------------------------------|--------|
| January, 01 2011 00:00:00+0000 |  April, 03 2011 00:00:00+0000 |     NY |
|   April, 03 2011 00:00:00+0000 |   June, 30 2011 00:00:00+0000 |     NJ |
|    June, 30 2011 00:00:00+0000 |   July, 20 2011 00:00:00+0000 |     CA |
|    July, 20 2011 00:00:00+0000 | August, 05 2011 00:00:00+0000 |     NY |
CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '16.09.2011', 'DD.MM.YYYY' ), TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), TO_DATE( '29.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '05.10.2011', 'DD.MM.YYYY' ), TO_DATE( '20.10.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH change_in_groups AS (
  SELECT t.*,
         CASE WHEN t."from"   = LAG( t."to"     ) OVER ( ORDER BY "from" )
              AND  t."stayed" = LAG( t."stayed" ) OVER ( ORDER BY "from" )
              THEN 0
              ELSE 1
              END AS has_changed_group
  FROM   tbl t
),
groups AS (
  SELECT "from",
         "to",
         "stayed"
         ,SUM( has_changed_group ) OVER ( ORDER BY "from" ) AS grp
  FROM   change_in_groups
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       MAX( "stayed" ) AS "stayed"
FROM   groups
GROUP BY grp
ORDER BY "from"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |
WITH leaves AS (
  SELECT CONNECT_BY_ROOT "from" AS "from",
         "to",
         "stayed",
         CONNECT_BY_ISLEAF AS leaf
  FROM   tbl t
  CONNECT BY PRIOR "stayed" = "stayed"
         AND PRIOR "to"     = "from"
)
SELECT MIN( "from" ) AS "from",
       "to",
       MIN( "stayed" ) AS "stayed"
FROM   leaves
WHERE  leaf = 1
GROUP BY "to"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |
查询1

CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH groups AS (
  SELECT t.*,
         ROW_NUMBER() OVER ( ORDER BY "from" ) - ROW_NUMBER() OVER ( PARTITION BY "stayed" ORDER BY "from" ) AS grp
  FROM   tbl t
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       "stayed"
FROM   groups
GROUP BY "stayed", grp
ORDER BY "from"
|                           FROM |                            TO | STAYED |
|--------------------------------|-------------------------------|--------|
| January, 01 2011 00:00:00+0000 |  April, 03 2011 00:00:00+0000 |     NY |
|   April, 03 2011 00:00:00+0000 |   June, 30 2011 00:00:00+0000 |     NJ |
|    June, 30 2011 00:00:00+0000 |   July, 20 2011 00:00:00+0000 |     CA |
|    July, 20 2011 00:00:00+0000 | August, 05 2011 00:00:00+0000 |     NY |
CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '16.09.2011', 'DD.MM.YYYY' ), TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), TO_DATE( '29.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '05.10.2011', 'DD.MM.YYYY' ), TO_DATE( '20.10.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH change_in_groups AS (
  SELECT t.*,
         CASE WHEN t."from"   = LAG( t."to"     ) OVER ( ORDER BY "from" )
              AND  t."stayed" = LAG( t."stayed" ) OVER ( ORDER BY "from" )
              THEN 0
              ELSE 1
              END AS has_changed_group
  FROM   tbl t
),
groups AS (
  SELECT "from",
         "to",
         "stayed"
         ,SUM( has_changed_group ) OVER ( ORDER BY "from" ) AS grp
  FROM   change_in_groups
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       MAX( "stayed" ) AS "stayed"
FROM   groups
GROUP BY grp
ORDER BY "from"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |
WITH leaves AS (
  SELECT CONNECT_BY_ROOT "from" AS "from",
         "to",
         "stayed",
         CONNECT_BY_ISLEAF AS leaf
  FROM   tbl t
  CONNECT BY PRIOR "stayed" = "stayed"
         AND PRIOR "to"     = "from"
)
SELECT MIN( "from" ) AS "from",
       "to",
       MIN( "stayed" ) AS "stayed"
FROM   leaves
WHERE  leaf = 1
GROUP BY "to"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |

CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH groups AS (
  SELECT t.*,
         ROW_NUMBER() OVER ( ORDER BY "from" ) - ROW_NUMBER() OVER ( PARTITION BY "stayed" ORDER BY "from" ) AS grp
  FROM   tbl t
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       "stayed"
FROM   groups
GROUP BY "stayed", grp
ORDER BY "from"
|                           FROM |                            TO | STAYED |
|--------------------------------|-------------------------------|--------|
| January, 01 2011 00:00:00+0000 |  April, 03 2011 00:00:00+0000 |     NY |
|   April, 03 2011 00:00:00+0000 |   June, 30 2011 00:00:00+0000 |     NJ |
|    June, 30 2011 00:00:00+0000 |   July, 20 2011 00:00:00+0000 |     CA |
|    July, 20 2011 00:00:00+0000 | August, 05 2011 00:00:00+0000 |     NY |
CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '16.09.2011', 'DD.MM.YYYY' ), TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), TO_DATE( '29.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '05.10.2011', 'DD.MM.YYYY' ), TO_DATE( '20.10.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH change_in_groups AS (
  SELECT t.*,
         CASE WHEN t."from"   = LAG( t."to"     ) OVER ( ORDER BY "from" )
              AND  t."stayed" = LAG( t."stayed" ) OVER ( ORDER BY "from" )
              THEN 0
              ELSE 1
              END AS has_changed_group
  FROM   tbl t
),
groups AS (
  SELECT "from",
         "to",
         "stayed"
         ,SUM( has_changed_group ) OVER ( ORDER BY "from" ) AS grp
  FROM   change_in_groups
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       MAX( "stayed" ) AS "stayed"
FROM   groups
GROUP BY grp
ORDER BY "from"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |
WITH leaves AS (
  SELECT CONNECT_BY_ROOT "from" AS "from",
         "to",
         "stayed",
         CONNECT_BY_ISLEAF AS leaf
  FROM   tbl t
  CONNECT BY PRIOR "stayed" = "stayed"
         AND PRIOR "to"     = "from"
)
SELECT MIN( "from" ) AS "from",
       "to",
       MIN( "stayed" ) AS "stayed"
FROM   leaves
WHERE  leaf = 1
GROUP BY "to"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |
编辑:

要回答您随后的编辑-这里有一种解决方法:

Oracle 11g R2架构设置

CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH groups AS (
  SELECT t.*,
         ROW_NUMBER() OVER ( ORDER BY "from" ) - ROW_NUMBER() OVER ( PARTITION BY "stayed" ORDER BY "from" ) AS grp
  FROM   tbl t
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       "stayed"
FROM   groups
GROUP BY "stayed", grp
ORDER BY "from"
|                           FROM |                            TO | STAYED |
|--------------------------------|-------------------------------|--------|
| January, 01 2011 00:00:00+0000 |  April, 03 2011 00:00:00+0000 |     NY |
|   April, 03 2011 00:00:00+0000 |   June, 30 2011 00:00:00+0000 |     NJ |
|    June, 30 2011 00:00:00+0000 |   July, 20 2011 00:00:00+0000 |     CA |
|    July, 20 2011 00:00:00+0000 | August, 05 2011 00:00:00+0000 |     NY |
CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '16.09.2011', 'DD.MM.YYYY' ), TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), TO_DATE( '29.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '05.10.2011', 'DD.MM.YYYY' ), TO_DATE( '20.10.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH change_in_groups AS (
  SELECT t.*,
         CASE WHEN t."from"   = LAG( t."to"     ) OVER ( ORDER BY "from" )
              AND  t."stayed" = LAG( t."stayed" ) OVER ( ORDER BY "from" )
              THEN 0
              ELSE 1
              END AS has_changed_group
  FROM   tbl t
),
groups AS (
  SELECT "from",
         "to",
         "stayed"
         ,SUM( has_changed_group ) OVER ( ORDER BY "from" ) AS grp
  FROM   change_in_groups
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       MAX( "stayed" ) AS "stayed"
FROM   groups
GROUP BY grp
ORDER BY "from"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |
WITH leaves AS (
  SELECT CONNECT_BY_ROOT "from" AS "from",
         "to",
         "stayed",
         CONNECT_BY_ISLEAF AS leaf
  FROM   tbl t
  CONNECT BY PRIOR "stayed" = "stayed"
         AND PRIOR "to"     = "from"
)
SELECT MIN( "from" ) AS "from",
       "to",
       MIN( "stayed" ) AS "stayed"
FROM   leaves
WHERE  leaf = 1
GROUP BY "to"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |
查询2

CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH groups AS (
  SELECT t.*,
         ROW_NUMBER() OVER ( ORDER BY "from" ) - ROW_NUMBER() OVER ( PARTITION BY "stayed" ORDER BY "from" ) AS grp
  FROM   tbl t
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       "stayed"
FROM   groups
GROUP BY "stayed", grp
ORDER BY "from"
|                           FROM |                            TO | STAYED |
|--------------------------------|-------------------------------|--------|
| January, 01 2011 00:00:00+0000 |  April, 03 2011 00:00:00+0000 |     NY |
|   April, 03 2011 00:00:00+0000 |   June, 30 2011 00:00:00+0000 |     NJ |
|    June, 30 2011 00:00:00+0000 |   July, 20 2011 00:00:00+0000 |     CA |
|    July, 20 2011 00:00:00+0000 | August, 05 2011 00:00:00+0000 |     NY |
CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '16.09.2011', 'DD.MM.YYYY' ), TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), TO_DATE( '29.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '05.10.2011', 'DD.MM.YYYY' ), TO_DATE( '20.10.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH change_in_groups AS (
  SELECT t.*,
         CASE WHEN t."from"   = LAG( t."to"     ) OVER ( ORDER BY "from" )
              AND  t."stayed" = LAG( t."stayed" ) OVER ( ORDER BY "from" )
              THEN 0
              ELSE 1
              END AS has_changed_group
  FROM   tbl t
),
groups AS (
  SELECT "from",
         "to",
         "stayed"
         ,SUM( has_changed_group ) OVER ( ORDER BY "from" ) AS grp
  FROM   change_in_groups
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       MAX( "stayed" ) AS "stayed"
FROM   groups
GROUP BY grp
ORDER BY "from"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |
WITH leaves AS (
  SELECT CONNECT_BY_ROOT "from" AS "from",
         "to",
         "stayed",
         CONNECT_BY_ISLEAF AS leaf
  FROM   tbl t
  CONNECT BY PRIOR "stayed" = "stayed"
         AND PRIOR "to"     = "from"
)
SELECT MIN( "from" ) AS "from",
       "to",
       MIN( "stayed" ) AS "stayed"
FROM   leaves
WHERE  leaf = 1
GROUP BY "to"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |

CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH groups AS (
  SELECT t.*,
         ROW_NUMBER() OVER ( ORDER BY "from" ) - ROW_NUMBER() OVER ( PARTITION BY "stayed" ORDER BY "from" ) AS grp
  FROM   tbl t
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       "stayed"
FROM   groups
GROUP BY "stayed", grp
ORDER BY "from"
|                           FROM |                            TO | STAYED |
|--------------------------------|-------------------------------|--------|
| January, 01 2011 00:00:00+0000 |  April, 03 2011 00:00:00+0000 |     NY |
|   April, 03 2011 00:00:00+0000 |   June, 30 2011 00:00:00+0000 |     NJ |
|    June, 30 2011 00:00:00+0000 |   July, 20 2011 00:00:00+0000 |     CA |
|    July, 20 2011 00:00:00+0000 | August, 05 2011 00:00:00+0000 |     NY |
CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '16.09.2011', 'DD.MM.YYYY' ), TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), TO_DATE( '29.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '05.10.2011', 'DD.MM.YYYY' ), TO_DATE( '20.10.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH change_in_groups AS (
  SELECT t.*,
         CASE WHEN t."from"   = LAG( t."to"     ) OVER ( ORDER BY "from" )
              AND  t."stayed" = LAG( t."stayed" ) OVER ( ORDER BY "from" )
              THEN 0
              ELSE 1
              END AS has_changed_group
  FROM   tbl t
),
groups AS (
  SELECT "from",
         "to",
         "stayed"
         ,SUM( has_changed_group ) OVER ( ORDER BY "from" ) AS grp
  FROM   change_in_groups
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       MAX( "stayed" ) AS "stayed"
FROM   groups
GROUP BY grp
ORDER BY "from"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |
WITH leaves AS (
  SELECT CONNECT_BY_ROOT "from" AS "from",
         "to",
         "stayed",
         CONNECT_BY_ISLEAF AS leaf
  FROM   tbl t
  CONNECT BY PRIOR "stayed" = "stayed"
         AND PRIOR "to"     = "from"
)
SELECT MIN( "from" ) AS "from",
       "to",
       MIN( "stayed" ) AS "stayed"
FROM   leaves
WHERE  leaf = 1
GROUP BY "to"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |
使用分层查询的替代解决方案:

查询3

CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH groups AS (
  SELECT t.*,
         ROW_NUMBER() OVER ( ORDER BY "from" ) - ROW_NUMBER() OVER ( PARTITION BY "stayed" ORDER BY "from" ) AS grp
  FROM   tbl t
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       "stayed"
FROM   groups
GROUP BY "stayed", grp
ORDER BY "from"
|                           FROM |                            TO | STAYED |
|--------------------------------|-------------------------------|--------|
| January, 01 2011 00:00:00+0000 |  April, 03 2011 00:00:00+0000 |     NY |
|   April, 03 2011 00:00:00+0000 |   June, 30 2011 00:00:00+0000 |     NJ |
|    June, 30 2011 00:00:00+0000 |   July, 20 2011 00:00:00+0000 |     CA |
|    July, 20 2011 00:00:00+0000 | August, 05 2011 00:00:00+0000 |     NY |
CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '16.09.2011', 'DD.MM.YYYY' ), TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), TO_DATE( '29.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '05.10.2011', 'DD.MM.YYYY' ), TO_DATE( '20.10.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH change_in_groups AS (
  SELECT t.*,
         CASE WHEN t."from"   = LAG( t."to"     ) OVER ( ORDER BY "from" )
              AND  t."stayed" = LAG( t."stayed" ) OVER ( ORDER BY "from" )
              THEN 0
              ELSE 1
              END AS has_changed_group
  FROM   tbl t
),
groups AS (
  SELECT "from",
         "to",
         "stayed"
         ,SUM( has_changed_group ) OVER ( ORDER BY "from" ) AS grp
  FROM   change_in_groups
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       MAX( "stayed" ) AS "stayed"
FROM   groups
GROUP BY grp
ORDER BY "from"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |
WITH leaves AS (
  SELECT CONNECT_BY_ROOT "from" AS "from",
         "to",
         "stayed",
         CONNECT_BY_ISLEAF AS leaf
  FROM   tbl t
  CONNECT BY PRIOR "stayed" = "stayed"
         AND PRIOR "to"     = "from"
)
SELECT MIN( "from" ) AS "from",
       "to",
       MIN( "stayed" ) AS "stayed"
FROM   leaves
WHERE  leaf = 1
GROUP BY "to"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |

CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH groups AS (
  SELECT t.*,
         ROW_NUMBER() OVER ( ORDER BY "from" ) - ROW_NUMBER() OVER ( PARTITION BY "stayed" ORDER BY "from" ) AS grp
  FROM   tbl t
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       "stayed"
FROM   groups
GROUP BY "stayed", grp
ORDER BY "from"
|                           FROM |                            TO | STAYED |
|--------------------------------|-------------------------------|--------|
| January, 01 2011 00:00:00+0000 |  April, 03 2011 00:00:00+0000 |     NY |
|   April, 03 2011 00:00:00+0000 |   June, 30 2011 00:00:00+0000 |     NJ |
|    June, 30 2011 00:00:00+0000 |   July, 20 2011 00:00:00+0000 |     CA |
|    July, 20 2011 00:00:00+0000 | August, 05 2011 00:00:00+0000 |     NY |
CREATE TABLE tbl ( "from", "to", "stayed" ) AS
          SELECT TO_DATE( '01.01.2011', 'DD.MM.YYYY' ), TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '03.04.2011', 'DD.MM.YYYY' ), TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '25.05.2011', 'DD.MM.YYYY' ), TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '04.06.2011', 'DD.MM.YYYY' ), TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '20.06.2011', 'DD.MM.YYYY' ), TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), 'NJ' FROM DUAL
UNION ALL SELECT TO_DATE( '30.06.2011', 'DD.MM.YYYY' ), TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '05.07.2011', 'DD.MM.YYYY' ), TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), 'CA' FROM DUAL
UNION ALL SELECT TO_DATE( '20.07.2011', 'DD.MM.YYYY' ), TO_DATE( '05.08.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '16.09.2011', 'DD.MM.YYYY' ), TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '20.09.2011', 'DD.MM.YYYY' ), TO_DATE( '29.09.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL
UNION ALL SELECT TO_DATE( '05.10.2011', 'DD.MM.YYYY' ), TO_DATE( '20.10.2011', 'DD.MM.YYYY' ), 'NY' FROM DUAL;
WITH change_in_groups AS (
  SELECT t.*,
         CASE WHEN t."from"   = LAG( t."to"     ) OVER ( ORDER BY "from" )
              AND  t."stayed" = LAG( t."stayed" ) OVER ( ORDER BY "from" )
              THEN 0
              ELSE 1
              END AS has_changed_group
  FROM   tbl t
),
groups AS (
  SELECT "from",
         "to",
         "stayed"
         ,SUM( has_changed_group ) OVER ( ORDER BY "from" ) AS grp
  FROM   change_in_groups
)
SELECT MIN( "from" ) AS "from",
       MAX( "to" ) AS "to",
       MAX( "stayed" ) AS "stayed"
FROM   groups
GROUP BY grp
ORDER BY "from"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |
WITH leaves AS (
  SELECT CONNECT_BY_ROOT "from" AS "from",
         "to",
         "stayed",
         CONNECT_BY_ISLEAF AS leaf
  FROM   tbl t
  CONNECT BY PRIOR "stayed" = "stayed"
         AND PRIOR "to"     = "from"
)
SELECT MIN( "from" ) AS "from",
       "to",
       MIN( "stayed" ) AS "stayed"
FROM   leaves
WHERE  leaf = 1
GROUP BY "to"
|                             FROM |                               TO | STAYED |
|----------------------------------|----------------------------------|--------|
|     April, 03 2011 00:00:00+0000 |      June, 30 2011 00:00:00+0000 |     NJ |
|   January, 01 2011 00:00:00+0000 |     April, 03 2011 00:00:00+0000 |     NY |
|      June, 30 2011 00:00:00+0000 |      July, 20 2011 00:00:00+0000 |     CA |
|      July, 20 2011 00:00:00+0000 |    August, 05 2011 00:00:00+0000 |     NY |
| September, 16 2011 00:00:00+0000 | September, 29 2011 00:00:00+0000 |     NY |
|   October, 05 2011 00:00:00+0000 |   October, 20 2011 00:00:00+0000 |     NY |

您可能想分析查询,但从解释计划来看,分层查询似乎更有效。

您也可以发布查询吗?可能重复我添加了另一个数据集,与以前的记录之间存在差异抱歉,我错过了纽约的双重条目。看看这里,这是一个非常类似的问题:非常感谢,它工作得很好。我没有想到这一排;-)更新了另外两个查询-这两个查询都将处理您的新编辑。