SQL Server:按组和序列

时间:2017-08-01 03:55:06

标签: sql-server sql-server-2008-r2

我在一些似乎应该非常简单的事情上遇到了困难,但我现在已经太累了,不能再惹它了所以我只是把它扔到这里,看看是否有人可以展示如何解决这个问题。 我试图做的是根据IDENTITY列(ID)排序的表中的值所属的序列,序列和顺序来识别表的行。 我使用的是Microsoft SQL Server 2008 R2 Management Studio(v10.50.4000.0)。

declare @X table (
ID int identity,
Value varchar(20)
);

insert @X
select 'abc'
union all
select 'zzz' --def
union all
select 'abc'
union all
select 'abc'
union all
select 'xyz'
union all
select 'abc'
union all
select 'abc';

select * from @X;

最终结果应如下所示:

/*
*GO-GroupOrder; SO-SequenceOrder; GSO-GroupSequenceOrder
ID  Value   GO  SO  GSO
1   abc     1   1   1
2   zzz     2   2   1 --def
3   abc     1   3   2
4   abc     1   3   2
5   xyz     3   4   1
6   abc     1   5   3
7   abc     1   5   3
*/

我希望我能够免除你迄今为止所做的各种失败的尝试(包括row_number,rank,dense_rank,group by等)。我相信必须有一个相对简单的解决方案,它不会涉及整个集合中的单个操作,但我无法弄清楚。 注意:编辑值def def to zzz以使请求的排序更清晰。 我希望这有意义并提前感谢!

解决方案:

with
    cte1 as (
        select
            x.ID,
            x.Value,
            oX.ValuePrevious
        from @X as x
        outer apply (
            select
                top 1
                    oX.Value as ValuePrevious
            from @X as oX
            where x.ID > oX.ID
            order by oX.ID desc
            ) as oX
        ),
    cte2 as (
        select
            min(ID) as IDMin,
            Value
        from @x
        group by Value
        ),
    cte3 as (
        select
            cte1.ID,
            cte1.Value,
            dense_rank() over (order by cte2.IDMin) as [GO],
            cCTE1.SO
        from cte1
        cross apply (
            select
                sum(case 
                    when 1 <> 1
                        or cCTE1.ValuePrevious != cCTE1.[Value]
                        or cCTE1.ValuePrevious is NULL
                    then 1
                    else 0
                    end) as SO
            from cte1 as cCTE1
            where cte1.ID >= cCTE1.ID
            ) as cCTE1
        join cte2
            on cte2.Value = cte1.Value
        )
    select
        ID,
        Value,
        [GO],
        SO,
        dense_rank() over (partition by [GO] order by SO) as [GSO]
    from cte3 order by ID;

1 个答案:

答案 0 :(得分:1)

如果我理解正确,您的查询将是

 ;WITH temp AS
(
    select  x.ID,
            x.[Value], 
            pre.PreviousValue      
    from @X x
    OUTER APPLY
    (
        SELECT  TOP 1 
                x2.[Value] AS PreviousValue
        FROM @X x2
        WHERE x2.ID < x.ID
        ORDER BY x2.ID DESC
    ) pre
),
temp1 AS
(
    SELECT x2.[Value], min(x2.ID) AS MinGrId
    FROM @X x2
    GROUP BY x2.[Value]
),
temp2 AS
(
select  t.*,
       SUM(CASE 
             WHEN t.PreviousValue != t.[Value] OR t.PreviousValue IS null THEN 1 
             ELSE 0
          END) OVER(ORDER BY t.ID) AS [SO],
        dense_rank() OVER(ORDER BY t1.MinGrId) AS [GO]
from temp t    
INNER JOIN temp1 t1 ON t.[Value] = t1.[Value]
)
SELECT t.ID, t.[Value], t.[GO], t.SO,
      dense_rank() OVER(PARTITION BY t.[GO] ORDER BY t.SO) AS GSO
FROM temp2 t
ORDER BY t.ID

演示链接:http://rextester.com/KGYT17255