SQL Server逻辑分组最近的时间

时间:2011-03-22 19:16:01

标签: sql sql-server-2008 grouping

我正在寻找解决这个问题的最佳方法,到目前为止还没有任何运气。 我正在使用Microsoft SQL Server 2008。

以下是用户的示例数据:

======================

名称状态日期

======================

BOB Active 2011-03-07

BOB Active 2011-03-11

BOB已禁用2011-03-15

BOB已禁用2011-03-21

BOB Active 2011-03-23

BOB Active 2011-03-28

======================

我希望将其分组,以便在用户实际更改状态时显示,而不是在下次检查时结果是否保持不变,以便查询返回的内容如下:

======================

BOB Active 2011-03-07

BOB已禁用2011-03-15

BOB Active 2011-03-23

======================

这是我没有任何访问权限的数据。

关于以我需要的方式获取此数据的最佳方法的任何想法?请记住,这是针对成千上万的记录,如果可能的话,应该考虑性能。我想不出一种方法来进行分组,这样它就不会将“激活”组合在一起并使用MIN聚合函数。

有没有办法可以循环并使数据看起来像这样在最后一列上进行分组和分组?这甚至是最好的方法吗?

======================

名称状态日期组

======================

BOB Active 2011-03-07 1

BOB Active 2011-03-11 1

BOB已禁用2011-03-15 2

BOB已停用2011-03-21 2

BOB Active 2011-03-23 3

BOB Active 2011-03-28 3

======================

我的所有搜索都没有成功,如果有人可以给我一个关键词来搜索让我走上正确的道路,我将非常感激。

2 个答案:

答案 0 :(得分:1)

select tb.name,tb.status,tb.date 
from the_table tb
join (select name,min(date) as date from the_table group by name) t_aggr on tb.name=t_aggr.name and tb.date=t_aggr.date
union
select tb2.name,tb2.status,tb2.date
from the_table tb1
join the_table tb2 on tb1.name=tb2.name and tb1.status<>tb2.status and tb2.date>tb1.date
left join the_table tb3 on tb1.name=tb2.name and tb1.date<tb3.date and tb3.date<tb2.date
where tb3.date is null

联合中的第一个选择是获得第一个记录。第二个应该得到改变。无论如何测试它,因为我没有sql服务器来尝试它。

答案 1 :(得分:0)

如果您使用的是SQL Server 2005或更新版本(您就是这样!),您可以通过对日期进行排名并加入上一个日期来轻松检测状态的变化。这将为您提供所需:

WITH rankedDates AS (
    SELECT name, status, date, row_number() OVER (PARTITION BY name ORDER BY DATE) as dateRank
    FROM #myTable
)
SELECT curr.name, curr.status, curr.date
FROM rankedDates curr
LEFT JOIN rankedDates prev
    ON curr.name = prev.name
    AND curr.dateRank = prev.dateRank+1
WHERE prev.status IS NULL
    OR curr.status <> prev.status

有些sql用来创建我用来制作这个函数的测试数据(我扔进了Jake,以确保它可以处理两个人):

SELECT 'BOB' AS name, 'Active' AS status, '2011-03-07' AS date  
INTO #myTable
UNION ALL
SELECT 'BOB', 'Active', '2011-03-11' UNION ALL
SELECT 'BOB', 'Disabled', '2011-03-15' UNION ALL
SELECT 'BOB', 'Disabled', '2011-03-21' UNION ALL
SELECT 'BOB', 'Active', '2011-03-23' UNION ALL
SELECT 'BOB', 'Active', '2011-03-28' 
--include below lines for more complex example
UNION ALL
SELECT 'JAKE', 'Active', '2011-01-11' UNION ALL
SELECT 'JAKE', 'Disabled', '2011-01-15' UNION ALL
SELECT 'JAKE', 'Disabled', '2011-05-21' UNION ALL
SELECT 'JAKE', 'Active', '2011-05-23' UNION ALL
SELECT 'JAKE', 'Active', '2011-07-28'

关于性能,如果你有名字的ID,名称上的索引,日期也会更好。