计算连续行之间的值更改并过滤SQL Server

时间:2017-09-29 15:59:55

标签: sql sql-server

我必须有一张跟踪某些设备版本的表格。该表用于跟踪任何版本升级,并且设备在一天中的不同时间ping它们的版本。最近,我注意到如果一个用户使用/注册另一个设备,那么对于同一个用户,该表将在同一天ping多个版本。遗憾的是,我无法更改此表的基础架构或将版本ping收集到不同的表集中的逻辑。

现在问题是当其中一个设备发生版本升级时,该表将显示给定日期的两个不同版本,这是正确的,但是由于用户有另一个设备,我也获得该设备的版本。

我的目标是过滤掉任何有超过1个设备的ID。现在在下面的示例中假设9.X是Android设备,所有1.X版本都是ios。在这种情况下,123有两个设备,我需要从数据集中删除123以进行进一步分析。我需要跟踪合法升级,所以在下面的情况下,只有234和345是1台设备的合法升级。虽然123的第一台设备将ios从1.6升级到1.7但我不能在分析中包含它因为123 id有另一台设备android 9.0。

123    1.7    2017-08-11 22:57:54.307
123    9.0    2017-08-11 21:37:54.307 <-- 123 second device version
123    1.7    2017-08-11 20:27:54.307
123    1.7    2017-08-11 19:17:54.307 <-- 123 first device version upgrade
123    1.6    2017-08-11 18:47:54.307
123    1.6    2017-08-11 17:37:54.307
123    9.0    2017-08-11 16:57:54.307 <-- 123 signed up with a new device
123    1.6    2017-08-11 15:17:54.307 <-- 123 first device version

234    1.7    2017-08-11 22:47:54.307
234    1.7    2017-08-11 21:47:54.307 <-- 234 first device version upgrade
234    1.5    2017-08-11 20:47:54.307
234    1.5    2017-08-11 19:47:54.307
234    1.5    2017-08-11 18:47:54.307 <-- 234 first device version

345    1.8    2017-08-11 22:47:54.307
345    1.8    2017-08-11 21:47:54.307 <-- 345 first device version upgrade
345    1.4    2017-08-11 20:47:54.307
345    1.4    2017-08-11 19:47:54.307
345    1.4    2017-08-11 18:47:54.307 <-- 345 first device version

我的脚本为我提供了正确的升级,但没有使用多于1个设备过滤那些ID。我需要在第一步中执行此操作,以便在最终数据集中不包含123。

;with device_versions as
(
    select  id, 
            ver, 
            row_no = ROW_NUMBER() OVER (partition by id order by MAX(dt_create) desc),  
            dt_create = MAX(dt_create),
            case
                when ver like '1.0%' then 'ios'
                else 'android'
            end device_name
    from dbo.version_history
    group by id, ver
)
select *,ios_row_no = ROW_NUMBER() over (partition by id order by min(dt_create) asc)
into #temp
from device_versions
where id in (select id from device_versions where row_no > 1 )
group by id,ver,row_no,dt_create,device_name
order by row_no

select id,ver,row_no,dt_create,device_name,ios_row_no
into #temp_final
from #temp a
where device_name='android' and   
ios_row_no = (select MAX(ios_row_no) from #temp b where a.id=b.id
and device_name='android')  

select a.id, dt_create = MIN(a.dt_create)
from #temp_final b
  JOIN dbo.version_history a
    ON  a.id = b.id
    AND a.dt_create > b.dt_create 
where  device_name ='android' 
group by a.id
union
select a.id, dt_create = MIN(a.dt_create)
from #temp b
  JOIN dbo.version_history a
    ON  a.id = b.id
    AND a.dt_create > b.dt_create
where  row_no = 2 and a.id not in (select id from #temp where device_name like 'ios')
group by a.id
union
select a.id,  MIN(a.dt_create)
from #temp b
  JOIN dbo.version_history a
    ON  a.id = b.id
where   a.id not in (select id from #temp where device_name like 'android')
group by a.id

drop table #temp
drop table #temp_final

当前输出 - 我需要在第一步中过滤掉123

123    
234    
345    

预期输出 - 我的脚本适用于具有单个设备和合法升级的所有ID。

234    
345    

2 个答案:

答案 0 :(得分:1)

使用LEAD()。

<强> 1)

select id,ver,lead(id,1) over (order by id,dt_create desc) as next_id,lead(ver,1) over (order by id,dt_create desc ) as next_ver,dt_create
into #temp1
from Z_version
order by id,dt_create desc

id  ver next_id next_ver    dt_create
123 1.7 123 9.0 2017-08-11 22:57:54.307
123 9.0 123 1.7 2017-08-11 21:37:54.307
123 1.7 123 1.7 2017-08-11 20:27:54.307
123 1.7 123 1.6 2017-08-11 19:17:54.307
123 1.6 123 1.6 2017-08-11 18:47:54.307
123 1.6 123 9.0 2017-08-11 17:37:54.307
123 9.0 123 1.6 2017-08-11 16:57:54.307
123 1.6 123 1.6 2017-08-11 15:17:54.307
123 1.6 123 1.6 2017-07-11 22:57:54.307
123 1.6 123 1.6 2017-07-11 21:37:54.307
123 1.6 123 1.6 2017-07-11 20:27:54.307
123 1.6 234 1.7 2017-07-11 19:17:54.307
234 1.7 234 1.7 2017-08-11 22:47:54.307
234 1.7 234 1.5 2017-08-11 22:47:54.307
234 1.5 234 1.5 2017-08-11 20:47:54.307
234 1.5 234 1.5 2017-08-11 19:47:54.307
234 1.5 234 1.5 2017-08-11 18:47:54.307
234 1.5 234 1.3 2017-07-11 22:47:54.307
234 1.3 234 1.3 2017-07-11 20:47:54.307
234 1.3 234 1.3 2017-07-11 19:47:54.307
234 1.3 345 1.8 2017-07-11 18:47:54.307
345 1.8 345 1.8 2017-08-11 22:47:54.307
345 1.8 345 1.4 2017-08-11 21:47:54.307
345 1.4 345 1.4 2017-08-11 20:47:54.307
345 1.4 345 1.4 2017-08-11 19:47:54.307
345 1.4 345 1.4 2017-08-11 18:47:54.307
345 1.4 NULL    NULL    2017-07-11 06:34:35.307

<强> 2)

select * into #temp2 from #temp1 where ver<>next_ver and id=next_id

id  ver next_id next_ver    dt_create
123 1.7 123 9.0 2017-08-11 22:57:54.307
123 9.0 123 1.7 2017-08-11 21:37:54.307
123 1.7 123 1.6 2017-08-11 19:17:54.307
123 1.6 123 9.0 2017-08-11 17:37:54.307
123 9.0 123 1.6 2017-08-11 16:57:54.307
234 1.7 234 1.5 2017-08-11 22:47:54.307
234 1.5 234 1.3 2017-07-11 22:47:54.307
345 1.8 345 1.4 2017-08-11 21:47:54.307

第3)

select id,convert(varchar(12),dt_create,112) as each_day,count(ver) as ver_count into #temp3 from #temp2
group by id,convert(varchar(12),dt_create,112) order by id

id  each_day    ver_count
123 20170811    5
234 20170711    1
234 20170811    1
345 20170811    1

<强> 4)

select id,max(ver_count) max_count into #temp4 from #temp3 group by id

id  max_count
123 5
234 1
345 1

<强> 5)

select id,max_count from #temp4 where max_count < 2 

id  max_count
234 1
345 1

<强> 6)

drop table #temp1
drop table #temp2
drop table #temp3
drop table #temp4

答案 1 :(得分:0)

如果我理解你的问题,也许这会简化它。

示例

Select Top 1 With Ties *
 From  YourTable
 Where ID not in (Select ID From YourTable Group By ID having floor(min(ver))<>floor(max(ver)))
 Order By Row_Number() over (Partition by id order by dt_create desc)

<强>返回

id   ver    dt_create
234  1.7    2017-08-11 22:47:54.307
345  1.8    2017-08-11 22:47:54.307
  

编辑 - 按ID划分,日期

;with cte as (
Select *
      ,VerCnt = sum(1)   over (partition by id,cast(dt_create as date))
      ,VerMin = min(ver) over (partition by id,cast(dt_create as date))
      ,VerMax = max(ver) over (partition by id,cast(dt_create as date))
 From  @YourTable 
)
Select top 1 with ties
       id,ver,dt_create
 From  cte
 Where floor(VerMin)=floor(VerMax)
   and VerCnt>1
 Order By Row_Number() over (Partition by id order by dt_create desc)