【问题标题】:SQL Server: Row ordering by group and sequenceSQL Server:按组和序列进行行排序
【发布时间】:2017-08-01 03:55:06
【问题描述】:

我在一些看起来应该很简单的事情上遇到了困难,但我现在太累了,不能再搞砸了,所以我只是把它扔在这里,看看是否有人可以展示如何解决这个问题。 我正在尝试根据 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 等)是可以接受的……;我确信必须有一个相对简单的解决方案,它只涉及整个集合中的单个操作,但我无法弄清楚。 注意:将值定义为 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;

【问题讨论】:

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


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

    【讨论】:

    • 我忘了提到我使用的是 Microsoft SQL Server 2008 R2 Management Studio (v10.50.4000.0),所以我无法使用 LAG 功能。然而,快速搜索让我找到了这个 (stackoverflow.com/questions/33283205/…),这可能会帮助我为那件作品做同样的事情。此外,排序需要按照 ID(标识列)而不是值的顺序。谢谢。
    • 在 sql server 2008 中,您可以使用 APPLY 代替 LAG 并按每个组的最小 id 排序项目。我编辑了我的答案。
    • 不幸的是,我正在使用古老的技术 (2008 R2),因此 ORDER BY 不能与聚合窗口函数一起使用 (stackoverflow.com/questions/12686140/…)。但也许这会帮助我修复那块 (stackoverflow.com/questions/38216962/…)。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多