SQL-分组依据以查找是否仅在某个值后跟某个其他值

时间:2018-08-06 11:37:20

标签: sql sql-server group-by aggregate-functions

我在下表中有这个

App No  EventCode   Event Date
---------------------------------------------------------
1        A          2010-01-01
1        B          2010-01-02
1        C          2010-01-03
1        A          2010-01-10
2        A          2010-01-04
2        C          2010-01-05
2        B          2010-01-06
3        A          2010-01-01
3        D          2010-01-11
4        A          2011-01-01
4        D          2011-01-02
4        C          2011-03-03

我需要确定App No是否至少有一个事件A,然后是事件C,而中间没有事件B。请告知是否可以使用按应用程序编号分组。我已经有一个复杂的查询,可以按应用程序编号分组以计算各种值。我需要将这一点与之整合。

结果表应类似于

[App No]    [A Immediately Followed By C]   [Max A date]
-------------------------------------------------------
1              0                            2010-01-10
2              1                            2010-01-04
3              0                            2010-01-01
4              1                            2011-01-01

3 个答案:

答案 0 :(得分:1)

我不记得通过聚合来解决此问题的方法,但是您可以对SQL Server 2008+使用LEAD()(可以在SQL SERVER 2012+中使用)或ROW_NUMBER()。

这是示例数据和临时表。

...阅读完有关问题的评论后,更新版本

CREATE TABLE #table_name (
    app_no int,
    event_code char(1),
    event_date date
);

insert into #table_name
    values
    (1,'A',GETDATE()-100),
    (1,'B',GETDATE()-10),
    (1,'C',GETDATE()-1),
    (2,'A',GETDATE()+10),
    (2,'A',GETDATE()+1),
    (2,'D',GETDATE()),
    (2,'C',GETDATE()+10),
    (3,'A',GETDATE()),
    (3,'C',GETDATE()+100)

select *
    ,ROW_NUMBER() over (partition by 1 order by app_no) as rowid
into #table_name2
from #table_name
where event_code in ('A','B','C')

select org.app_no
    ,org.event_code
    ,case 
        when rez2.event_code is not null then 1 
        else 0 
    end as 'A followed by C'
    ,case 
        when rez2.max_date is not null then rez2.max_date 
        else org.event_date
    end as 'Max A date'
from #table_name2 org
left outer join (
    select t1.*,d.max_date
    from #table_name2 t1
    inner join #table_name2 t2 on t2.rowid=t1.rowid+1
    left outer join
    (
        select app_no,event_code,MAX(event_date) as max_date
        from #table_name
        group by app_no,event_code
    )d on d.app_no=t1.app_no and d.event_code=t1.event_code
    where t1.event_code='A' and t2.event_code='C'
)rez2 on rez2.app_no=org.app_no and rez2.event_code=org.event_code and rez2.event_date=org.event_date
where org.event_code='A'

drop table #table_name
drop table #table_name2

答案 1 :(得分:1)

为此,您应使用lead()进行汇总和过滤:

select appno,
       (case when max(case when eventcode = 'A' and next_ec = 'C' then 1 else 0 end) > 0
             then 1 else 0
        end) as flag,
       max(case when eventcode = 'A' then date end) as max_a_date
from (select t.*,
             lead(eventcode) over (partition by appno order by date) as next_ec
      from t
      where eventcode <> 'B'
     ) t
group by appno;

编辑:

在SQL Server 2008中,您可以执行以下操作:

select appno,
       (case when max(case when eventcode = 'A' and next_ec = 'C' then 1 else 0 end) > 0
             then 1 else 0
        end) as flag,
       max(case when eventcode = 'A' then date end) as max_a_date
from (select t.*,
             t2.eventcode as next_ec
      from t outer apply
           (select top (1) t2.*
            from t t2
            where t2.appno = t.appno and t2.date > t.date
            order by t2.date desc
           ) tnext
      where eventcode <> 'B'
     ) t
group by appno;

答案 2 :(得分:0)

;WITH cte
AS
(
    SELECT tn.app_no
        ,tn.event_code
        ,tn.event_date
        ,LEAD(tn.event_code) OVER (PARTITION BY tn.app_no ORDER BY tn.event_date) NextEvent
    FROM <Your_Table> AS tn
)

SELECT app_no
    ,MAX(CASE WHEN cte.NextEvent='C'
              THEN 1
         ELSE 0
     END) AS [A Immediately Followed By C]
    ,MAX(event_date) event_date
FROM cte
WHERE event_code='A'
GROUP BY app_no