求某列按分组连续编号的最大区间差异值

求一句SQL,求连续记录的最大个数
create table #t 
(_id varchar(3), _date int) 

insert #t select '001',20100101 
union all select '001',20100102 
union all select '002',20100103 
union all select '002',20100101 
union all select '002',20100102 
union all select '002',20100104
union all select '001',20100105 
union all select '001',20100106 
union all select '001',20100107 
union all select '002',20100105 
union all select '002',20100107 
union all select '002',20100108 
union all select '003',20100101
union all select '003',20100102
union all select '003',20100104
union all select '003',20100105
union all select '003',20100106
union all select '003',20100108
union all select '003',20100109
union all select '003',20100111

要求: 求出每个ID 的最大连续记录的个数。记录有几百万, 效率要好一点。 谢谢!
结果为:001最大连续为从20100105到20100107,数量为3, 
  002最大连续为从20100101到20100104,数量为4, 
  003最大连续为从20100104到20100106,数量为3
===================
001 3
002 4
003 3
===================
如果不影响效率的话,最好把时间段也带上:
=================================
001 3 20100105 20100107
002 4 20100101 20100104
003 3 20100104 20100106
=================================
要能加条件, 比如查询连续数量大于3的,结果只有一条
======================================
002 4 20100101 20100104

 

 

--SQL2000

 

if OBJECT_ID('tempdb..#t') is not null drop table #t
go
create table #t 
(id
varchar(3), date int

insert #t select '001',20100101 
union all select '001',20100102 
union all select '002',20100103 
union all select '002',20100101 
union all select '002',20100102 
union all select '002',20100104
union all select '001',20100105 
union all select '001',20100106 
union all select '001',20100107 
union all select '002',20100105 
union all select '002',20100107 
union all select '002',20100108 
union all select '003',20100101
union all select '003',20100102
union all select '003',20100104
union all select '003',20100105
union all select '003',20100106
union all select '003',20100108
union all select '003',20100109
union all select '003',20100111

--1.
alter table #t add d int
go
declare @i int, @j int,@k int
update #t set
    d
= @j,
   
@j = case when @i = id then @j else isnull(@j,0)+1 end,
   
@i = id
--2.

if OBJECT_ID('tempdb..#') is not null drop table #
go
select *,0 c into # from #t order by d,date
go
declare @i int, @j int,@k int
update # set
    c
= @j,
   
@j = case when @i = id and @k=date-1 then @j +1 else 1 end,
   
@i = id,
   
@k=dateselect ID,MAX(c) 最大连续数量 from # group by ID

/*
ID   最大连续数量
---- -----------
001  3
002  4
003  3

(3 行受影响)
*/

 

 

--SQL2005:

 

 

--1.更新分区段的行
declare @i int, @j int,@k int
update #t set d = @j,@j = case when @i = _id then @j else isnull(@j,0)+1 end,@i = _id
--2.查询
;with t1 as
(
   
select _id,d, _date1 = _date - row_number() over (partition by d order by _date),_date
   
from #t
)
,t2
as
(
   
select _id, d, cnt = count(1),mindate=MIN(_date),maxdate= MAX(_date)
   
from t1
   
group by _id, d, _date1 ) select _id, maxcnt = max(cnt),
    mindate
=(select mindate from t2 where cnt=max(t.cnt) and _id=t._id),
    maxdate
=(select maxdate from t2 where cnt=max(t.cnt) and _id=t._id)
from t2 t
group by _id

/*
_id  maxcnt      mindate     maxdate
---- ----------- ----------- -----------
001  3           20100105    20100107
002  4           20100101    20100104
003  3           20100104    20100106

(3 行受影响)
*/
原贴:http://topic.csdn.net/u/20100402/17/1565fb1e-f1e0-4961-b0c4-ae41f95c550f.html?21618

线段树是一种非常高效的数据结构,它通常用于处理区间查询问题,例如区间最大、最小、总和等。在线段树区间最大的问题中,线段树允许我们快速地对一个区间内的元素进行查询和修改操作。 线段树的构建过程是这样的:首先,我们将一个包含n个元素的数组构建为一个完全二叉树,其中每个节点代表原始数组中的一个区间。对于数组中的每个元素,它对应树中的叶子节点,而根节点则代表整个数组的区间[0, n-1]。对于非叶子节点,它的左子节点代表区间[l, mid],右子节点代表区间[mid+1, r],其中mid=(l+r)/2。 构建线段树后,进行区间最大查询的过程如下: 1. 从根节点开始,判断查询区间是否与当前节点代表的区间完全重合。如果是,则直接返回当前节点的最大。 2. 如果查询区间部分重合,递归地在左子区间或右子区间(或两者)中进行查询。 3. 最后,合并从左右子区间得到的最大,返回查询区间最大。 此外,如果数组中的元素发生变化,线段树还支持快速更新操作。当我们更新数组中的一个元素时,只需要在对应的叶子节点更新线段树,并递归地向上更新父节点的,直到根节点。 以下是使用C++实现线段树区间最大的一个简单示例代码: ```cpp #include <iostream> #include <algorithm> using namespace std; const int MAXN = 100005; // 根据实际情况定义数组的最大长度 int segtree[4 * MAXN]; // 分配足够大的空间,线段树从1开始索引 // 构建线段树 void build(int node, int start, int end, int arr[]) { if (start == end) { segtree[node] = arr[start]; // 叶子节点直接存储数组元素 } else { int mid = (start + end) / 2; build(node * 2, start, mid, arr); // 构建左子树 build(node * 2 + 1, mid + 1, end, arr); // 构建右子树 segtree[node] = max(segtree[node * 2], segtree[node * 2 + 1]); // 合并子区间最大 } } // 查询区间最大 int query(int node, int start, int end, int L, int R) { if (R < start || end < L) { return INT_MIN; // 区间不相交时返回最小 } if (L <= start && end <= R) { return segtree[node]; // 完全包含在查询区间内时直接返回 } int mid = (start + end) / 2; int max_left = query(node * 2, start, mid, L, R); // 查询左子区间 int max_right = query(node * 2 + 1, mid + 1, end, L, R); // 查询右子区间 return max(max_left, max_right); // 返回左右子区间最大的较大者 } int main() { int arr[MAXN]; // 假设已经填充了arr数组 build(1, 0, MAXN - 1, arr); // 从根节点开始构建线段树 // 假设要查询区间[L, R]的最大 int L = ...; // 起始位置 int R = ...; // 结束位置 cout << "区间最大为: " << query(1, 0, MAXN - 1, L, R) << endl; return 0; } ``` 在上述代码中,我们没有包含具体的数组数据和查询区间,因为这些信息依赖于具体的问题场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值