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