【问题标题】:Returning a table based on multiple columns返回基于多列的表
【发布时间】:2014-11-26 13:21:25
【问题描述】:

在下面的示例表中,如果适用,我需要一个脚本在 S 的第一个实例之前返回 event_type CP 的最后一个实例。主要比较是最近的 event_date。 如果日期重复,则决胜局将是最高的 event_id。

person_id   event_date          event_id    event_type
78          08/12/2010 00:00    706         CP
78          09/12/2010 00:00    707         CP
107         23/02/2010 00:00    93          CP
107         21/09/2012 00:00    1474        S
217         18/02/2010 00:00    158         S
364         26/01/2011 00:00    1122        CP
364         19/02/2011 00:00    569         S
367         21/06/2010 00:00    151         CP
367         01/07/2010 00:00    247         S
369         26/07/2010 00:00    248         S
369         27/07/2010 00:00    152         CP
481         07/09/2010 00:00    194         CP
481         07/09/2010 00:00    289         S
502         13/08/2010 00:00    200         CP
530         14/06/2010 00:00    220         CP
535         05/07/2010 00:00    222         CP
535         26/07/2010 00:00    224         CP
536         23/08/2010 00:00    225         CP
631         15/12/2009 00:00    256         CP
632         18/09/2010 00:00    259         CP
643         18/09/2010 00:00    261         CP
653         30/09/2010 00:00    360         S
653         15/10/2010 00:00    295         CP
653         15/10/2010 00:00    298         CP
680         30/09/2010 00:00    281         CP
680         30/11/2010 00:00    480         CP
689         06/10/2010 00:00    372         S
689         02/11/2010 00:00    306         CP
689         02/11/2010 00:00    370         CP
689         26/08/2011 00:00    1944        CP
689         27/08/2011 00:00    1947        CP
689         22/09/2011 00:00    2125        CP
689         06/11/2012 00:00    2720        CP
689         13/11/2012 00:00    2752        CP
689         15/11/2012 00:00    2765        CP
729         15/09/2010 00:00    299         CP
811         27/10/2010 00:00    413         S
834         06/01/2012 00:00    1233        S
849         21/02/2011 00:00    336         CP
984         13/11/2010 00:00    384         CP
984         18/11/2010 00:00    392         CP
984         18/11/2010 00:00    395         CP
984         19/11/2010 00:00    394         CP
1066        11/11/2010 00:00    472         S
1066        23/11/2010 00:00    408         CP
1109        23/12/2010 00:00    428         CP
1109        19/07/2011 00:00    958         S
1190        02/12/2010 00:00    499         CP
1193        03/12/2010 00:00    504         CP
1194        03/12/2010 00:00    505         CP
1199        19/11/2010 00:00    511         CP
1199        19/11/2010 00:00    501         S
1199        05/12/2010 00:00    526         CP
1199        08/12/2010 00:00    568         CP
1199        16/12/2010 00:00    704         CP
1199        16/12/2010 00:00    705         CP
1199        23/12/2010 00:00    803         CP
1199        24/12/2010 00:00    809         CP
1199        31/12/2010 00:00    851         CP
1199        11/01/2011 00:00    926         CP
1199        15/02/2011 00:00    1119        CP
1199        03/03/2011 00:00    1116        CP
1199        28/07/2011 00:00    1726        CP
1199        26/08/2011 00:00    1943        CP
1199        03/09/2011 00:00    1984        CP
1199        21/09/2011 00:00    2064        CP
1209        05/12/2010 00:00    524         CP
1210        05/12/2010 00:00    525         CP
1383        20/12/2010 00:00    798         CP
1386        20/12/2010 00:00    799         CP
1404        23/12/2010 00:00    801         CP
1405        23/12/2010 00:00    802         CP
1444        31/12/2010 00:00    849         CP
1445        31/12/2010 00:00    850         CP
1535        11/01/2011 00:00    924         CP
1536        11/01/2011 00:00    925         CP
1565        09/01/2011 00:00    979         CP
1623        27/01/2011 00:00    531         S
1661        25/01/2011 00:00    1046        CP
1662        25/01/2011 00:00    1047        CP
1663        25/01/2011 00:00    1048        CP
1665        25/01/2011 00:00    1049        CP
1666        23/01/2011 00:00    1050        CP
1667        01/02/2011 00:00    1052        CP
1741        14/02/2011 00:00    1111        CP
1752        15/02/2011 00:00    1118        CP
1781        04/10/2010 00:00    1868        CP
1781        04/10/2010 00:00    1869        CP
1781        04/10/2010 00:00    1870        CP
1781        10/02/2011 00:00    1052        S
1781        25/03/2011 00:00    1867        CP
1781        26/09/2011 00:00    2103        CP
1841        02/02/2011 00:00    1165        CP
1841        28/02/2011 00:00    597         S
1845        13/06/2011 00:00    1608        CP
1845        14/06/2011 00:00    1605        CP
1845        16/06/2011 00:00    1602        CP
1845        16/06/2011 00:00    1609        CP
1845        16/06/2011 00:00    1610        CP
1880        22/07/2011 00:00    1684        CP
1887        11/03/2011 00:00    1231        CP
1887        18/03/2011 00:00    607         S
1903        02/06/2011 00:00    1551        CP
1913        25/03/2011 00:00    1301        CP
1913        31/03/2011 00:00    1354        CP
2054        11/05/2011 00:00    1447        CP
2054        12/05/2011 00:00    780         S
2103        03/04/2011 00:00    1417        CP
2109        17/04/2011 00:00    1422        CP
2123        09/04/2011 00:00    1434        CP
2123        05/05/2011 00:00    769         S
2187        20/01/2011 00:00    1475        CP
2187        29/01/2011 00:00    803         S
2222        12/05/2011 00:00    1501        CP
2246        31/05/2011 00:00    1536        CP
2246        02/06/2011 00:00    1539        CP
2246        01/07/2012 00:00    1448        S
2246        29/07/2012 00:00    2569        CP
2246        06/08/2012 00:00    2586        CP
2306        06/05/2011 00:00    918         S
2456        15/09/2011 00:00    2065        CP
2456        02/12/2013 00:00    1694        S
2456        29/01/2014 00:00    3340        CP
2456        01/10/2014 00:00    3661        CP
2459        24/08/2011 00:00    1859        CP
2476        17/08/2011 00:00    1039        S
2512        17/09/2011 00:00    2049        CP
2512        26/01/2012 00:00    1256        S
2516        24/08/2011 00:00    1857        CP
2630        03/09/2011 00:00    1982        CP
2630        13/05/2013 00:00    3064        CP
2691        22/09/2011 00:00    2135        CP
2694        20/04/2011 00:00    2053        CP
2694        30/04/2011 00:00    1112        S
2759        07/11/2011 00:00    1165        S
2759        09/01/2012 00:00    2271        CP
2759        09/02/2012 00:00    2377        CP
2773        24/01/2013 00:00    2920        CP
2773        25/01/2013 00:00    1430        S
2773        14/02/2013 00:00    2946        CP
2858        27/10/2011 00:00    2209        CP
2858        08/11/2011 00:00    1167        S
2892        05/11/2011 00:00    1172        S
2896        09/11/2011 00:00    1174        S
2961        15/08/2012 00:00    2591        CP
3041        28/03/2012 00:00    2441        CP
3041        29/03/2012 00:00    2442        CP
3178        08/09/2012 00:00    2611        CP
3251        13/11/2012 00:00    2744        CP
3263        28/11/2012 00:00    2802        CP
3294        14/12/2012 00:00    2826        CP
3311        01/02/2013 00:00    1534        S
3344        30/04/2013 00:00    1566        S
3344        03/05/2013 00:00    3045        CP
3362        07/02/2013 00:00    2980        CP
3362        06/04/2013 00:00    1555        S
3426        22/05/2013 00:00    3086        CP
3457        29/11/2012 00:00    1574        S
3612        10/11/2012 00:00    3551        CP
3770        03/01/2014 00:00    3379        CP
3770        10/01/2014 00:00    1766        S
3805        04/03/2014 00:00    1782        S
3881        05/04/2014 00:00    3550        CP
3901        15/02/2014 00:00    3584        CP
3901        02/03/2014 00:00    1820        S
3907        04/11/2013 00:00    1821        S
3907        06/01/2014 00:00    3591        CP
3907        14/01/2014 00:00    3592        CP
3907        14/01/2014 00:00    3593        CP
4040        10/05/2014 00:00    3660        CP
4040        15/05/2014 00:00    3659        CP
4040        20/05/2014 00:00    1866        S

【问题讨论】:

    标签: sql sql-server tsql sql-server-2005


    【解决方案1】:

    使用 ROW_NUMBER() 的示例,在 SQL Server 2005 中受支持:

    [编辑:如果您的真实数据集存在某些 person_id 没有 S 类型或某些 person_id 有多个 S 实例的情况,此版本会稍微稳健一些(这将获得 S 的第一个实例,只有其他代码在第一个实例之前)]

        with tab as
    (
    select 3907 as person_id, 2457 as event_id, '01/09/2013 00:00' as event_date, 'CP' as event_type
    union
    select 3907 as person_id, 2896 as event_id, '09/09/2013 00:00' as event_date, 'CP' as event_type
    union
    select 3907 as person_id, 1866 as event_id, '20/05/2014 00:00' as event_date, 'S' as event_type
    union
    select 4040 as person_id, 3660 as event_id, '10/05/2014 00:00' as event_date, 'CP' as event_type
    union
    select 4040 as person_id, 3659 as event_id, '15/05/2014 00:00' as event_date, 'CP' as event_type
    union
    select 4040 as person_id, 1866 as event_id, '20/05/2014 00:00' as event_date, 'S' as event_type
    )
    ,personsAndFirst_S_Type as
    (
        select
            person_id,
            min(event_date) as first_S_EventDate
        from tab
        where event_type = 'S'
        group by person_id
    )
    ,
    numberedTab as
    (
        select
            *,
            ROW_NUMBER() OVER(PARTITION BY person_id ORDER BY event_type, event_date, event_id) as rn
        from tab
    )
    ,maxRn as
    (
        select
            person_id,
            max(rn) as maxNonSRow
        from numberedTab nt
        where nt.event_type <> 'S'
        group by person_id
    )
    select
        numberedTab.person_id,
        numberedTab.event_id, 
        numberedTab.event_date,
        numberedTab.event_type
    from numberedTab
    inner join maxRn
        on numberedTab.rn = maxRn.maxNonSRow
        and numberedTab.person_id = maxRn.person_id
    inner join personsAndFirst_S_Type s
        on numberedTab.person_id = s.person_id
        and numberedTab.event_date < s.first_S_EventDate
    

    使用 TSQL 的 Lead 函数根据您想要对这些分区进行分区和排序的方式获取每一行的下一行的 event_type 列。

    MSDN Page on TSQL LEAD Function

    with tab as
    (
    select 3907 as person_id, 2457 as event_id, '01/09/2013 00:00' as event_date, 'CP' as event_type
    union
    select 3907 as person_id, 2896 as event_id, '09/09/2013 00:00' as event_date, 'CP' as event_type
    union
    select 3907 as person_id, 1866 as event_id, '20/05/2014 00:00' as event_date, 'S' as event_type
    union
    select 4040 as person_id, 3660 as event_id, '10/05/2014 00:00' as event_date, 'CP' as event_type
    union
    select 4040 as person_id, 3659 as event_id, '15/05/2014 00:00' as event_date, 'CP' as event_type
    union
    select 4040 as person_id, 1866 as event_id, '20/05/2014 00:00' as event_date, 'S' as event_type
    ),
    tabWithNextEventTypeOnRow as
    (
        select
            *,
            LEAD(event_type) OVER(PARTITION BY person_id ORDER BY event_date) as nxtEventType
        from tab
    )
    select
        *
    from tabWithNextEventTypeOnRow
    where nxtEventType = 'S'
    

    【讨论】:

    • LEAD 仅在 SQL Server 2012 或更高版本中受支持。 OP 在问题中标记了 SQL Server 2005 的标记。
    • 我没看到。感谢您指出这一点,Krishnraj。这是一个使用 ROW_NUMBER() 的额外步骤 CTE 版本,它在 SQL Server 2005 中受支持。
    • @Bpa 没有 LEAD() 函数的脚本会返回我修改后的表中除了 person_id 值 1199、1781、2246、2456、2773 之外的所有必需行。这似乎是因为这些 person_id 实例在 S 的第一个实例之后和 S 的第一个实例之前都有 CP 实例。这些可以在您的脚本中处理吗?谢谢
    【解决方案2】:

    如果我理解正确,那么这就是你想要的。

    架构

    Declare @table1 table (person_id int, event_id int, event_date varchar(30), event_type varchar(5))
    insert into @table1 values 
    (3907,2457 ,'01/09/2013', 'CP'),
    (3907,2896 ,'09/09/2013', 'CP'),
    (3907,1866  ,'20/05/2013', 'S'),
    (4040,3660 ,'10/05/2014', 'CP'),
    (4040,3659 ,'15/05/2014', 'CP'),
    (4040,1866 ,'20/05/2014', 'S')
    

    查询

    SELECT person_id, event_id, event_date, event_type
    FROM (
        SELECT *
            ,ROW_NUMBER() OVER (
                PARTITION BY person_id ORDER BY event_date DESC
                ) rownum
        FROM @table1
        WHERE event_type = 'CP'
        ) t
    WHERE rownum = 1
    

    输出

    person_id   event_id    event_date  event_type
    3907        2896         09/09/2013   CP
    4040        3659         10/05/2014   CP
    

    【讨论】:

    • 这将只返回每个人的最后一个 cp,op 想要第一个 s 之前的最后一个 cp
    • @Krishnraj Rana 感谢您的更新,但您的脚本每个 person_id 返回多行。我现在添加了一个更全面的表格。不使用 LEAD() 函数的 Bpa 脚本有一个很好的尝试,但它只返回在 S 的第一个实例之前具有 CP 实例的 person_id 实例的行。它省略了具有 event_type 实例的 person_id 值在 S 的第一个实例之前和之后的 CP 值。抱歉,如果这个解释有点啰嗦!
    【解决方案3】:

    您可以使用not exists 选择第一个S 之前的所有CProw_number() 选择这些行中的最后一个CP(即第一个CP 之前的最后一个CP

    select * from (
        select *, 
        row_number() over (partition by person_id order by event_date desc) rn
        from (
            select * 
            from mytable t1
            where not exists (
                select 1 from mytable t2
                where t2.event_type = 'S'
                and t2.person_id = t1.person_id
                and t2.event_date < t1.event_date
            ) and event_type = 'CP'
        ) t1 
    ) t1 where rn = 1
    

    【讨论】:

    • LEAD 仅在 SQL Server 2012 或更高版本中受支持。 OP 在问题中标记了 SQL Server 2005 的标记。
    【解决方案4】:

    与 except 语句的联合返回所有需要的行——即使是在 S 的第一个实例之前和之后都有 CP 实例的行。 我确信一定有比这更有效的解决方案,但时间和资源目前不属于我!

    select person_id,event_date,event_id,rn from 
       (select *, 
        row_number() over (partition by person_id order by event_date desc, event_id desc) rn
        from (select * 
          from mytable t1
          where not exists 
          (select 1 from mytable t2
            where t2.event_type = 'S' AND
            t2.person_id = t1.person_id AND
            t2.event_date <= t1.event_date) 
            AND event_type = 'CP') t1) t1 where rn = 1
    union
    select person_id,event_date,event_id,rn from 
    (select *, 
    row_number() over (partition by person_id order by event_date desc, event_id desc) rn
    from (select * 
          from mytable t1
          where not exists 
          (select 1 from mytable t2
            where t2.event_type = 'S' AND
            t2.person_id = t1.person_id AND
            t2.event_date <> t1.event_date) 
            AND event_type = 'CP') t1) t1 where rn = 1
    except
    select person_id,event_date,event_id,rn from 
    (select *, 
    row_number() over (partition by person_id order by event_date desc, event_id desc) rn
    from (select * 
          from mytable t1
          where not exists 
          (select 1 from mytable t2
            where t2.event_type = 'S' AND
            t2.person_id = t1.person_id AND
            t2.event_date <= t1.event_date) 
            AND event_type = 'CP') t1) t1 where rn = 1 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-01
      • 1970-01-01
      • 2020-07-29
      • 2018-07-11
      • 2015-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多