如何检查每个唯一ID的列值顺序(按日期)?

时间:2017-08-25 15:24:23

标签: sql sql-server

我有这张表,活动:

| ID | Date of activity    | activity |
|----|---------------------|----------|
| 1  | 2016-05-01T13:45:03 | a        |
| 1  | 2016-05-02T13:45:03 | b        |
| 1  | 2016-05-03T13:45:03 | a        |
| 1  | 2016-05-04T13:45:03 | b        |
| 2  | 2016-05-01T13:45:03 | b        |
| 2  | 2016-05-02T13:45:03 | b        |

和这张表:

| id | Right order |
|----|-------------|
| 1  | yes         |
| 2  | no          |

如果活动的顺序与此订单相似,我如何检查每个ID?

 a b a b a b  ..   

当然我会根据活动日期进行检查

3 个答案:

答案 0 :(得分:0)

在SQL Server 2012+中,您可以将common table expressionlag()一起使用,然后使用跟随您的逻辑的min()表达式的case,如下所示:

;with cte as (
  select *
      , prev_activity = lag(activity) over (partition by id order by date_of_activity)
  from t
)
select id
  , right_order = min(case
      when activity = 'a' and isnull(prev_activity,'b')<>'b' then 'no'
      when activity = 'b' and isnull(prev_activity,'b')<>'a' then 'no'
      else 'yes'
    end)
from cte
group by id

rextester演示:http://rextester.com/NQQF78056

返回:

+----+-------------+
| id | right_order |
+----+-------------+
|  1 | yes         |
|  2 | no          |
+----+-------------+

在SQL Server 2012之前,您可以使用outer apply()来获取之前的活动而不是lag(),如下所示:

select id
  , right_order = min(case
      when activity = 'a' and isnull(prev_activity,'b')<>'b' then 'no'
      when activity = 'b' and isnull(prev_activity,'b')<>'a' then 'no'
      else 'yes'
    end)
from t
  outer apply (
    select top 1 prev_activity = i.activity
    from t as i
    where i.id = t.id
      and i.date_of_activity < t.date_of_activity
    order by i.date_of_activity desc
    ) x
group by id

答案 1 :(得分:0)

  

EDITED - 允许每个ID的模式数量可变

也许是另一种方法

示例

Declare @Pat varchar(max)='a b'
Declare @Cnt int = 2

Select ID
      ,RightOrder = case when rtrim(replicate(@Pat+' ',Hits/@Cnt)) = (Select Stuff((Select ' ' +activity From t Where id=A.id order by date_of_activity For XML Path ('')),1,1,'') ) then 'Yes' else 'No' end
 From (Select ID,hits=count(*) from t group by id) A

<强>返回

ID  RightOrder
1   Yes
2   No

答案 2 :(得分:0)

select id,
case when sum(flag)=0 and cnt_per_id%2=0 
     and max(case when rnum=1 then activity end) = 'a' 
     and max(case when rnum=2 then activity end) = 'b' 
     and min_activity = 'a' and max_activity = 'b'
then 'yes' else 'no' end as RightOrder
from (select t.*
      ,row_number() over(partition by id order by activitydate) as rnum
      ,count(*) over(partition by id) as cnt_per_id
      ,min(activity) over(partition by id) as min_activity
      ,max(activity) over(partition by id) as max_activity
      ,case when lag(activity) over(partition by id order by activitydate)=activity then 1 else 0 end as flag
      from tbl t
     ) t
group by id,cnt_per_id,max_activity,min_activity

根据解释,必须为正确的顺序实施以下逻辑。

  • 检查每个id的行数是否均匀(如果可以存在奇数行,如a,b,a或a,b,a,b,a等,则删除此条件)
  • 第一行包含a和第二行b,最低活动为a,最高活动为b
  • 标记总和(使用lag设置)应为0