2015-11-09 59 views
1

我有一个表,看起来更不像是:MSSQL:DISTINCT这需要日期范围考虑

K_PKEY   D_FROM    D_TO     PERC 
============ ==================== ==================== =========== 
0013   01-JAN-2009 00:00:00 31-JUL-2011 00:00:00 
0013   01-AUG-2011 00:00:00 31-DEC-2011 00:00:00 
0013   01-JAN-2012 00:00:00 31-MAR-2012 00:00:00 
0013   01-APR-2012 00:00:00 31-DEC-2012 00:00:00 75.000000 
0013   01-JAN-2013 00:00:00 31-JAN-2013 00:00:00 50.000000 
0013   01-FEB-2013 00:00:00 28-FEB-2013 00:00:00 50.000000 
0013   01-MAR-2013 00:00:00 31-AUG-2013 00:00:00 75.000000 
0013   01-SEP-2013 00:00:00 31-MAY-2015 00:00:00 75.000000 
0013   01-JUN-2015 00:00:00 31-DEC-2100 00:00:00 

我试图建立一个DISTICT查询需要特定的日期范围考虑。

这是我想出了:

SELECT DISTINCT k_pkey, MIN(d_from), MAX(d_to), perc FROM my_table GROUP BY k_pkey 

它不工作的方式我想,我明白为什么。 MIN()和MAX()与DISTINCT结合在一起工作,这对于该类型的查询来说很自然。这导致:

K_PKEY   D_FROM    D_TO     PERC 
============ ==================== ==================== =========== 
0013   01-JAN-2009 00:00:00 31-DEC-2100 00:00:00 
0013   01-APR-2012 00:00:00 31-MAY-2015 00:00:00 75.000000 
0013   01-JAN-2013 00:00:00 28-FEB-2013 00:00:00 50.000000 

我想实现的是保持时间顺序,并结合只是范围被(这么说)彼此相邻。

K_PKEY   D_FROM    D_TO     PERC 
============ ==================== ==================== =========== 
0013   01-JAN-2009 00:00:00 31-MAR-2012 00:00:00 
0013   01-APR-2012 00:00:00 31-DEC-2012 00:00:00 75.000000 
0013   01-JAN-2013 00:00:00 28-FEB-2013 00:00:00 50.000000 
0013   01-MAR-2013 00:00:00 31-MAY-2015 00:00:00 75.000000 
0013   01-JUN-2015 00:00:00 31-DEC-2100 00:00:00 

是否有可能与一个SQL查询(我不想使用SQL过程,如果可能的话)?有什么建议么?

+0

的SQL Server版本?根据这个,你可能会看到窗口函数(OVER子句)。但我怀疑,我真的明白你的分组标准... – Shnugo

+0

我可能会使用游标清理数据并将清理过的数据插入临时表中。我将从第一条记录开始,存储它的开始和结束日期。然后,我会遍历数据集并修改开始日期和结束日期,以查找彼此相邻的范围。最后,我只是做一个选择不同的临时表中留下了什么。 –

+0

嗨,我正在使用MSSQL 2012 – PiWo

回答

2

您正试图将相邻的行组合在一起,根据日期和PERC是相同的。这个想法是使用left join来确定哪些值开始一个新的范围。然后,使用累计和计算每行开始的次数。后一个值可以用于分组。

在SQL Server 2012+中,累计和可以直接完成。在早期版本中,您将使用outer apply

结果查询是这样的:

select k_pkey, min(d_from) as d_from, max(d_to) as d_to, perc 
from (select t.*, 
      sum(IsGroupStart) over (partition by k_pkey, perc order by d_from) as grp 
     from (select t.*, 
        (case when t_prev.k_pkey is null then 1 else 0 end) as IsGroupStart 
      from t left join 
       t tprev 
       on tprev.k_pkey = t.k_pkey and 
        (tprev.perc = t.perc or tprev.perc is null and t.perc is null) and 
        tprev.d_to = dateadd(day, -1, t.d_from) 
      ) t 
    ) t 
group by grp, k_pkey, perc; 
+0

好!非常好! ;)@Gordon您怎么看待使用'LAG()'来查找新组何时开始? '(case is whennull((lag(e.perc)OVER(by d_from)), - 1)<> e.perc then 1 else 0 end)as NewGroup' –

+0

谢谢 - 我马上查一查,回到反馈,但它似乎正是我需要:) – PiWo

+0

@DavidIsla。 。 。 'LAG()'是一个合理的选择,而不是自联接。 –