我有一个场景,我有
Id|rank| date
1 | 7 |07/08/2015
1 | 7 |09/08/2015
1 | 8 |16/08/2015
1 | 8 |17/08/2015
1 | 7 |19/08/2015
1 | 7 |15/08/2015
2 | 7 |01/08/2015
2 | 7 |02/08/2015
2 | 8 |16/08/2015
2 | 8 |17/08/2015
2 | 7 |26/08/2015
2 | 7 |28/08/2015
我想要的解决方案是
1 | 7 |07/08/2015
1 | 8 |16/08/2015
1 | 7 |15/08/2015
2 | 7 |01/08/2015
2 | 8 |16/08/2015
2 | 7 |26/08/2015
即每个id和rank的块我想要最小的日期。 我已经尝试过使用while循环,因为有数千条记录需要2个小时才能加载。还有其他方法可以做。请建议。
答案 0 :(得分:1)
对于每一行,使用必要的顺序给出唯一的行号。 (因为我得到Id比日期更重要,日期比排名更重要)。
使用移动了一行(d1.RowNum = d2.RowNum+1
)的行号将结果表连接到自身。
仅选择加入“其他块”行(d1.Id <> d2.Id or d1.Rank <> d2.rank
)的行。
根据移动方向和选定的表格,将选择最大或最小日期。
不要忘记“边缘情况” - 由于移位导致的行无法连接(这就是为什么不使用inner join
和d1.RowNum = 1
条件。)
;WITH dataWithRowNums as (
select Id, Rank, Date,
RowNum = ROW_NUMBER() OVER (ORDER BY Id,date,rank)
from YourTable
)
select d1.Id, d1.Rank, d1.Date
from dataWithRowNums d1
left join dataWithRowNums d2
on d1.RowNum = d2.RowNum+1 and (d1.Id <> d2.Id or d1.Rank <> d2.rank)
where not d2.Id is null or d1.RowNum = 1
此代码返回与您的结果位不同的结果:
Id Rank Date
1 7 2015-08-07
1 8 2015-08-16
1 7 2015-08-19 <-- you've got here 2015-08-15
2 7 2015-08-01
2 8 2015-08-16
2 7 2015-08-26
由于区块(等级8 Id 1)已于16/08开始,所以排名7的第15/08行与第一个区块(排名7 Id1)相关。
如果您仍然需要排序(因此15/08等级7与第二个块(rank7 id1)相关),那么您应该提供自己的RowSorting数据,然后在这里询问另一个任务的另一个解决方案)
答案 1 :(得分:0)
以下是使用row_number()
的查询 ;WITH cte_rec
as (SELECT Id,Rank,Date
,ROW_NUMBER()OVER (partition by Id,Rank ORDER BY date) as RNO
FROM YourTable)
SELECT Id,Rank,Date
FROM cte_rec
WHERE RNO =1
答案 2 :(得分:0)
This is what I have tried and is running as expected
create table #temp
(
iden int identity(1,1),
ID int,
[rank] int,
[date] date,
dr_id int,
rownum_id int,
grouprecord int
)
Insert into #temp(id,rank,date)
select 1 , 7 ,'07/08/2015'
union all select 1 , 7 ,'09/08/2015'
union all select 1 , 8 ,'08/16/2015'
union all select 1 , 8 ,'08/17/2015'
union all select 1 , 7 ,'08/19/2015'
union all select 1 , 7 ,'08/15/2015'
union all select 2 , 7 ,'08/01/2015'
union all select 2 , 7 ,'08/02/2015'
union all select 2 , 8 ,'08/16/2015'
union all select 2 , 8 ,'08/17/2015'
union all select 2 , 7 ,'08/26/2015'
union all select 2 , 7 ,'08/28/2015'
update t1
set dr_id = t2.rn
from #temp t1 inner join
(select iden, dense_rank() over(order by id) as rn from #temp) t2
on t1.iden = t2.iden
update t1
set rownum_id = t2.rn
from #temp t1 inner join
(select iden, row_number() over(partition by dr_id order by id) as rn from #temp) t2
on t1.iden = t2.iden
select *,row_number() over(order by iden)rn into #temp1 from
(
select t2.*
from #temp t1 inner join #temp t2
on (t1.dr_id = t2.dr_id or t2.dr_id = (t1.dr_id +1) ) and ( t1.rank<>t2.rank or t2.dr_id = (t1.dr_id +1) )
and t2.iden = t1.iden + 1
)a
declare @id int,@miniden int,@maxiden int,@maxid int
set @id = 1
select @maxid = max(iden) from #temp
while exists(select 1 from #temp1 where rn = @id)
begin
Select @miniden = iden from #temp1
where rn = @id
Select @maxiden = iden from #temp1
where rn = @id+1
update #temp
set grouprecord = @id +1
where iden between @miniden and @maxiden
IF(@maxiden IS NULL)
BEGIN
Update #temp
set grouprecord = @id +1
where iden between @miniden and @maxid
END
set @id = @id + 1
SET @miniden =NULL
SET @maxiden = NULL
end
UPDATE #TEMP
SET GROUPRECORD = 1
WHERE GROUPRECORD IS NULL
select min(date) as mindate,grouprecord from #temp
group by grouprecord
谢谢大家的帮助:)