复杂的SQL排名/行号,忽略指定的类型和重置计数

时间:2013-08-02 22:45:09

标签: sql-server-2008 tsql

实际数据

colA    group_date  type    desc        actual_date     
ABC123  1/15/2013   A       TEST1       1/17/2013       
ABC123  1/15/2013   B       TEST1       1/17/2013       
ABC123  1/15/2013   A       TEST2       1/19/2013       
ABC123  1/15/2013   I       IGNORE_1    1/22/2013       
ABC123  3/15/2013   B       TEST3       3/20/2013       
XYZ456  6/10/2012   A       XYZTEST1    6/12/2012       
XYZ456  6/10/2012   B       XYZTEST2    6/13/2012       
XYZ456  6/10/2012   A       XYZTEST2    6/13/2012       
XYZ456  10/1/2012   B       XYZTEST3    10/5/2012       
XYZ456  11/15/2012  B       XYZTEST4    11/18/2012      
SSS999  4/10/2011   A       SSSTEST1    4/13/2011       
SSS999  4/10/2011   B       SSSTEST2    4/14/2011       
SSS999  4/10/2011   A       SSSTEST2    4/14/2011       
SSS999  4/10/2011   A       SSSTEST3    4/19/2011       
SSS999  8/5/2011    B       SSSTEST4    8/7/2011        
SSS999  8/5/2011    I       IGNORE_SSS1 8/14/2011       
SSS999  11/5/2011   B       XYZTEST4    11/18/2011      
SSS999  11/5/2011   B       XYZTEST5    11/20/2011      
SSS999  12/15/2011  B       XYZTEST6    12/16/2011      

我正试图找出一种方法来获得每个组的排名/行号。唯一的行号(应该递增,分区?)由colA,group_date,desc(按actual_date排序)组成。如果“desc”和“actual_date”记录相同,则应重复该数字,我相信我已经可以使用了。

我的问题是每次遇到“I”类型记录时都应该“重置”计数。这个“I”类型的记录可以被分配一个0的row_number,或者我的偏好将被省略,因为一旦获得了正确的行号,它将从表中删除...它仅供参考。

这是我目前的目标(包括可在最终查询中删除的“I”记录):

目标结果

colA    group_date  type    desc        actual_date     row_num
ABC123  1/15/2013   A       TEST1       1/17/2013       1
ABC123  1/15/2013   B       TEST1       1/17/2013       1
ABC123  1/15/2013   A       TEST2       1/19/2013       2
ABC123  1/15/2013   I       IGNORE_1    1/22/2013       0
ABC123  3/15/2013   B       TEST3       3/20/2013       1
XYZ456  6/10/2012   A       XYZTEST1    6/12/2012       1
XYZ456  6/10/2012   B       XYZTEST2    6/13/2012       2
XYZ456  6/10/2012   A       XYZTEST2    6/13/2012       2
XYZ456  10/1/2012   B       XYZTEST3    10/5/2012       3
XYZ456  11/15/2012  B       XYZTEST4    11/18/2012      4
SSS999  4/10/2011   A       SSSTEST1    4/13/2011       1
SSS999  4/10/2011   B       SSSTEST2    4/14/2011       2
SSS999  4/10/2011   A       SSSTEST2    4/14/2011       2
SSS999  4/10/2011   A       SSSTEST3    4/19/2011       3
SSS999  8/5/2011    B       SSSTEST4    8/7/2011        4
SSS999  8/5/2011    I       IGNORE_SSS1 8/14/2011       0
SSS999  11/5/2011   B       XYZTEST4    11/18/2011      1
SSS999  11/5/2011   B       XYZTEST5    11/20/2011      2
SSS999  12/15/2011  B       XYZTEST6    12/16/2011      3

1 个答案:

答案 0 :(得分:2)

以下是适用于您的数据的查询:

with ignore_count as
(
  select *
    , ignore_count = (select count(1) from MyTable i
                    where t.colA = i.colA
                    and t.group_date > i.group_date
                    and type = 'I')
  from MyTable t
  where type <> 'I'
)
, ranks as
(
  select colA
    , group_date
    , type
    , [desc]
    , actual_date
    , [row_num] = dense_rank() over (partition by colA, ignore_count
                                   order by group_date, actual_date)
  from ignore_count
)
select *
from ranks
order by colA
  , group_date
  , [row_num]
  , type

请参阅SQL Fiddle with demo

这里我通过检查I组中每行之前发生的colA行数来进行分组,以允许row_num重置发生,然后我使用了DENSE_RANK在每个colA组中排名,由I行分隔。

您会注意到我已删除I行以帮助查询;你提到这没关系。

适用于您的数据,但正如评论中所述,这看起来似乎非常复杂,因此答案可能不适用于整个数据集。

希望它可以让你走上正确的轨道,并且可以根据需要轻松调整。