执行排名取决于类别

时间:2018-05-18 08:39:06

标签: sql sql-server

我的表格如下:

RowNum    category     Rank4A     Rank4B
-------------------------------------------
1         A            
2         A
3         B
5         A
6         B
9         B

我的要求基于RowNum订单,使两个新的排名列依赖于类别。 Rank4A的工作方式与DENSERANK()的{​​{1}}类似,但如果该行用于类别B,则会按category = A推导出类别A订单的最新排名。 RowNum具有相似的逻辑,但按Rank4B顺序按RowNum排序。所以结果就是这样(DESC意味着这个单元格我不在乎它的价值):

W

另一个要求是,由于数据集较大,不允许RowNum category Rank4A Rank4B ------------------------------------------- 1 A 1 W 2 A 2 W 3 B 2 3 5 A 3 2 6 B W 2 9 B W 1 CROSS APPLY。任何简洁的解决方案?

编辑:也没有CTE(由于MAX 32767限制)

2 个答案:

答案 0 :(得分:2)

您可以使用以下查询:

SELECT RowNum, category, 
       SUM(CASE 
              WHEN category = 'A' THEN 1 
              ELSE 0 
       END) OVER (ORDER BY RowNum) AS Rank4A,
       SUM(CASE 
              WHEN category = 'B' THEN 1 
              ELSE 0 
       END) OVER (ORDER BY RowNum DESC) AS Rank4B

FROM mytable
ORDER BY RowNum

答案 1 :(得分:1)

Giorgos Betsos'答案更好,请先阅读。

试一试。我相信每个CTE都足够清晰,可以显示步骤。

IF OBJECT_ID('tempdb..#Data') IS NOT NULL
    DROP TABLE #Data

CREATE TABLE #Data (
    RowNum INT,
    Category CHAR(1))

INSERT INTO #Data (
    RowNum,
    Category)
VALUES
    (1, 'A'),
    (2, 'A'),
    (3, 'B'),
    (5, 'A'),
    (6, 'B'),
    (9, 'B')

;WITH AscendentDenseRanking AS 
(
    SELECT
        D.RowNum,
        D.Category,
        AscendentDenseRanking = DENSE_RANK() OVER (ORDER BY D.Rownum ASC)
    FROM
        #Data AS D
    WHERE
        D.Category = 'A'
),
LaggedRankingA AS
(
    SELECT
        D.RowNum,
        AscendentDenseRankingA = MAX(A.AscendentDenseRanking)
    FROM
        #Data AS D
        INNER JOIN AscendentDenseRanking AS A ON D.RowNum > A.RowNum
    WHERE
        D.Category = 'B'
    GROUP BY
        D.RowNum
),
DescendantDenseRanking AS 
(
    SELECT
        D.RowNum,
        D.Category,
        DescendantDenseRanking = DENSE_RANK() OVER (ORDER BY D.Rownum DESC)
    FROM
        #Data AS D
    WHERE
        D.Category = 'B'
),
LaggedRankingB AS
(
    SELECT
        D.RowNum,
        AscendentDenseRankingB = MAX(A.DescendantDenseRanking)
    FROM
        #Data AS D
        INNER JOIN DescendantDenseRanking AS A ON D.RowNum < A.RowNum
    WHERE
        D.Category = 'A'
    GROUP BY
        D.RowNum
)
SELECT
    D.RowNum,
    D.Category,
    Rank4A = ISNULL(RA.AscendentDenseRanking, LA.AscendentDenseRankingA),
    Rank4B = ISNULL(RB.DescendantDenseRanking, LB.AscendentDenseRankingB)
FROM
    #Data AS D
    LEFT JOIN AscendentDenseRanking AS RA ON D.RowNum = RA.RowNum
    LEFT JOIN LaggedRankingA AS LA ON D.RowNum = LA.RowNum
    LEFT JOIN DescendantDenseRanking AS RB ON D.RowNum = RB.RowNum
    LEFT JOIN LaggedRankingB AS LB ON D.RowNum = LB.RowNum


/*
Results:

    RowNum      Category Rank4A               Rank4B
    ----------- -------- -------------------- --------------------
    1           A        1                    3
    2           A        2                    3
    3           B        2                    3
    5           A        3                    2
    6           B        3                    2
    9           B        3                    1
*/

这不是递归CTE,因此限制32k不适用。