【问题标题】:SQL Server logical grouping most recent timeSQL Server 逻辑分组最近时间
【发布时间】:2011-03-22 19:16:01
【问题描述】:

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

所以这里是一个用户的样本数据:

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

姓名状态日期

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

BOB 活跃于 2011-03-07

鲍勃活跃于 2011 年 3 月 11 日

BOB 已禁用 2011-03-15

BOB 已禁用 2011-03-21

鲍勃活跃于 2011 年 3 月 23 日

鲍勃活跃于 2011 年 3 月 28 日

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

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

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

BOB 活跃于 2011-03-07

BOB 已禁用 2011-03-15

鲍勃活跃于 2011 年 3 月 23 日

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

这是我无权访问的数据。

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

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

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

名称状态日期组

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

BOB 活跃于 2011-03-07 1

BOB 活跃于 2011-03-11 1

BOB 已禁用 2011-03-15 2

BOB 已禁用 2011-03-21 2

BOB 活跃于 2011-03-23 3

BOB 活跃于 2011-03-28 3

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

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

【问题讨论】:

    标签: sql sql-server-2008 grouping


    【解决方案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
    

    union 中的第一个选择是获取第一条记录。第二个应该得到改变。无论如何测试它,因为我没有 sql server 可以尝试它。

    【讨论】:

    • 如果他想要按特定顺序排列结果,他可以按他想要的顺序排列......但记录是应该的。
    • 我注意到并删除了我的评论:-P
    【解决方案2】:

    如果您使用的是 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'
    

    关于性能,如果您有 name 的 ID 会更好,并且 name,date 的索引也会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-10
      • 1970-01-01
      • 1970-01-01
      • 2014-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-09
      相关资源
      最近更新 更多