如果您可以识别所有组及其起始set_id
,那么您可以使用递归方法并在单个语句中执行此操作,而不是需要迭代填充表。但是,为了提高速度/效率和资源消耗,您需要对这两种方法进行基准测试 - 无论是针对您的数据量还是在系统的可用资源范围内进行扩展,都需要进行验证。
如果我的理解,当你决定开始您就可以使用查询一次识别所有这些新组:
with t as (
select t1.type, t1.set_id, t1.min_value, t1.max_value,
t2.set_id as next_set_id, t2.min_value as next_min_value,
t2.max_value as next_max_value
from table1 t1
left join table1 t2 on t2.type = t1.type and t2.min_value > t1.max_value
where not exists (
select 1
from table1 t3
where t3.type = t1.type
and t3.max_value < t1.min_value
)
)
select t.type, t.set_id, t.min_value, t.max_value,
t.next_set_id, t.next_min_value, t.next_max_value,
row_number() over (order by t.type, t.min_value, t.next_min_value) as grp_id
from t
where not exists (
select 1 from t t2
where t2.type = t.type
and t2.next_max_value < t.next_min_value
)
order by grp_id;
棘手位这里获得所有三组a
,特别是二组以set_id = 1
开头,但d
只有一个组。内部select(在CTE中)通过not exists
子句查找没有较低非重叠范围的集合,并且外连接到同一个表以获取不重叠的下一个集合,为您提供了两个以set_id = 1
开头的组,还有四个以set_id = 9
开头。然后,外部选择将忽略除第二个子句以外的最低非重叠项 - 但不必再次打到真正的表。
所以,让你:
TYPE SET_ID MIN_VALUE MAX_VALUE NEXT_SET_ID NEXT_MIN_VALUE NEXT_MAX_VALUE GRP_ID
---- ------ ---------- ---------- ----------- -------------- -------------- ------
a 1 1 3 2 4 10 1
a 1 1 3 3 6 10 2
a 4 2 5 3 6 10 3
b 5 1 9 4
c 6 1 7 5
c 7 3 10 6
d 8 1 2 9 3 3 7
然后,您可以使用它作为锚定构件在recursive subquery factoring clause:
with t as (
...
),
r (type, set_id, min_value, max_value,
next_set_id, next_min_value, next_max_value, grp_id) as (
select t.type, t.set_id, t.min_value, t.max_value,
t.next_set_id, t.next_min_value, t.next_max_value,
row_number() over (order by t.type, t.min_value, t.next_min_value)
from t
where not exists (
select 1 from t t2
where t2.type = t.type
and t2.next_max_value < t.next_min_value
)
...
如果你离开了r
CTE与和刚刚做你” d得到相同的七个小组。
递归部件然后使用从该查询以各组的下一个成员的下set_id
其范围,并且重复外连接/不存在查找找到下一个(多个)集合再次;停车时没有下一组不重叠:
...
union all
select r.type, r.next_set_id, r.next_min_value, r.next_max_value,
t.set_id, t.min_value, t.max_value, r.grp_id
from r
left join table1 t
on t.type = r.type
and t.min_value > r.next_max_value
and not exists (
select 1 from table1 t2
where t2.type = r.type
and t2.min_value > r.next_max_value
and t2.max_value < t.min_value
)
where r.next_set_id is not null -- to stop looking when you reach a leaf node
)
...
最后您有一个基于递归CTE得到你想要的列和指定的顺序查询:
...
select r.type, r.grp_id, r.set_id
from r
order by r.type, r.grp_id, r.min_value;
它得到:
TYPE GRP_ID SET_ID
---- ---------- ----------
a 1 1
a 1 2
a 2 1
a 2 3
a 3 4
a 3 3
b 4 5
c 5 6
c 6 7
d 7 8
d 7 9
d 7 10
d 7 11
SQL Fiddle demo。
如果您想要显示每组的最小/最大值,并且可以跟踪并显示每组的最小/最大值。我只是显示了问题的列,但是。
你的例子只有有两个元素的结果。可以有两个以上吗? – 2014-11-14 19:32:36
是的!这只是为了简单。可能是从'1'到'10'的每个“值”都是一个单独的集合,因此是一个单独的元素。我会更新示例数据以显示此内容。 – esa606 2014-11-14 19:35:18
我认为你的过程很好,除了第1步和第2步。你可以用table1中的每一组初始化表。 – 2014-11-14 19:47:25