sql-server – 这是否需要递归CTE,只需要创意窗口函数,循环?

我不能为我的生活弄清楚如何获得X类别的分数的加权排名.例如,学生需要回答3个类别中的10个问题(问题#和类别#最终都是变量).要获得总分,每个X(3)类别中的前1个分数将被添加到剩余的任何内容中以添加总共10个问题分数.

这是数据.我使用了一个CASE WHEN Row_Number()来获取TopInCat

http://sqlfiddle.com/#!6/e6e9f/1

小提琴有更多的学生.

| Question | Student | Category | Score | TopInCat |
|----------|---------|----------|-------|----------|
|   120149 |     125 |        6 | 1     |        1 |
|   120127 |     125 |        6 | 0.9   |        0 |
|   120124 |     125 |        6 | 0.8   |        0 |
|   120125 |     125 |        6 | 0.7   |        0 |
|   120130 |     125 |        6 | 0.6   |        0 |
|   120166 |     125 |        6 | 0.5   |        0 |
|   120161 |     125 |        6 | 0.4   |        0 |
|   120138 |     125 |        4 | 0.15  |        1 |
|   120069 |     125 |        4 | 0.15  |        0 |
|   120022 |     125 |        4 | 0.15  |        0 |
|   120002 |     125 |        4 | 0.15  |        0 |
|   120068 |     125 |        2 | 0.01  |        1 |
|   120050 |     125 |        3 | 0.05  |        1 |
|   120139 |     125 |        2 | 0     |        0 |
|   120156 |     125 |        2 | 0     |        0 |

这就是我想象它需要看的方式,但它不一定是这个.我只需要通过3个类别的详细数据得到10个问题,这样我就可以对下面的排序1-10列进行求和. 999可能是无效的,只要我可以总结什么重要并提供细节.

| Question | Student | Category | Score | TopInCat | Sort |
|----------|---------|----------|-------|----------|------|
|   120149 |     125 |        6 | 1     |        1 |    1 |
|   120138 |     125 |        4 | 0.15  |        1 |    2 |
|   120068 |     125 |        2 | 0.01  |        1 |    3 |
|   120127 |     125 |        6 | 0.9   |        0 |    4 |
|   120124 |     125 |        6 | 0.8   |        0 |    5 |
|   120125 |     125 |        6 | 0.7   |        0 |    6 |
|   120130 |     125 |        6 | 0.6   |        0 |    7 |
|   120166 |     125 |        6 | 0.5   |        0 |    8 |
|   120161 |     125 |        6 | 0.4   |        0 |    9 |
|   120069 |     125 |        4 | 0.15  |        0 |   10 |
|   120022 |     125 |        4 | 0.15  |        0 |  999 |
|   120002 |     125 |        4 | 0.15  |        0 |  999 |
|   120050 |     125 |        3 | 0.05  |        1 |  999 |
|   120139 |     125 |        2 | 0     |        0 |  999 |
|   120156 |     125 |        2 | 0     |        0 |  999 |

最后一件事,一旦满足X(3)阈值,该类别就不再重要.所以第四类只是正常排序.

| Question | Student | Category | Score | TopInCat | Sort |
|----------|---------|----------|-------|----------|------|
|   120149 |     126 |        6 | 1     |        1 |    1 |
|   120138 |     126 |        4 | 0.75  |        1 |    2 |
|   120068 |     126 |        2 | 0.50  |        1 |    3 |
|   120127 |     126 |        6 | 0.9   |        0 |    4 |
|   120124 |     126 |        6 | 0.8   |        0 |    5 |
|   120125 |     126 |        6 | 0.7   |        0 |    6 |
|   120130 |     126 |        6 | 0.6   |        0 |    7 |
|   120166 |     126 |        6 | 0.5   |        0 |    8 |
|   120050 |     126 |        3 | 0.45  |        1 |    9 |********
|   120161 |     126 |        6 | 0.4   |        0 |   10 |
|   120069 |     126 |        4 | 0.15  |        0 |  999 |
|   120022 |     126 |        4 | 0.15  |        0 |  999 |
|   120002 |     126 |        4 | 0.15  |        0 |  999 |
|   120139 |     126 |        2 | 0     |        0 |  999 |
|   120156 |     126 |        2 | 0     |        0 |  999 |

我非常感谢任何帮助.几天来我一直在打扰我.

最佳答案 有了这些事情,我喜欢继续采用“积木式”方法.遵循首先使其工作的格言,然后如果你需要快速,这第一步通常就足够了.

所以,给定

CREATE TABLE WeightedScores
    ([Question] int, [Student] int, [Category] int, [Score] dec(3,2))
;

和你的样本数据

INSERT INTO WeightedScores
    ([Question], [Student], [Category], [Score])
VALUES
    (120161, 123, 6, 1),    (120166, 123, 6, 0.64),    (120138, 123, 4, 0.57),    (120069, 123, 4, 0.5),
    (120068, 123, 2, 0.33),    (120022, 123, 4, 0.18),    (120061, 123, 6, 0),    (120002, 123, 4, 0),
    (120124, 123, 6, 0),    (120125, 123, 6, 0),    (120137, 123, 6, 0),    (120154, 123, 6, 0),
    (120155, 123, 6, 0),   (120156, 123, 6, 0),    (120139, 124, 2, 1),    (120156, 124, 2, 1),
    (120050, 124, 3, 0.88),    (120068, 124, 2, 0.87),    (120161, 124, 6, 0.87),    (120138, 124, 4, 0.85),
    (120069, 124, 4, 0.51),    (120166, 124, 6, 0.5),    (120022, 124, 4, 0.43),    (120002, 124, 4, 0),
    (120130, 124, 6, 0),    (120125, 124, 6, 0),    (120124, 124, 6, 0),    (120127, 124, 6, 0),
    (120149, 124, 6, 0),    (120149, 125, 6, 1),    (120127, 125, 6, 0.9),    (120124, 125, 6, 0.8),
    (120125, 125, 6, 0.7),    (120130, 125, 6, 0.6),    (120166, 125, 6, 0.5),    (120161, 125, 6, 0.4),
    (120138, 125, 4, 0.15),    (120069, 125, 4, 0.15),    (120022, 125, 4, 0.15),    (120002, 125, 4, 0.15),
    (120068, 125, 2, 0.01),    (120050, 125, 3, 0.05),    (120139, 125, 2, 0),    (120156, 125, 2, 0),
    (120149, 126, 6, 1),    (120138, 126, 4, 0.75),    (120068, 126, 2, 0.50),    (120127, 126, 6, 0.9),
    (120124, 126, 6, 0.8),    (120125, 126, 6, 0.7),    (120130, 126, 6, 0.6),    (120166, 126, 6, 0.5),
    (120050, 126, 3, 0.45),    (120161, 126, 6, 0.4),    (120069, 126, 4, 0.15),    (120022, 126, 4, 0.15),
    (120002, 126, 4, 0.15),    (120139, 126, 2, 0),    (120156, 126, 2, 0)
;

我们继续吧

这里复杂的部分是确定前三个顶级问题;每个学生感兴趣的十个问题中的其他问题只是按分数排序,这很容易.因此,让我们首先确定排名前三的顶级问题.

首先,为每个行分配一个行号,为该学生分配该类别中该分数的顺序:

;WITH Numbered1 ( Question, Student, Category, Score, SeqInStudentCategory ) AS
(
    SELECT Question, Student, Category, Score
        , ROW_NUMBER() OVER (PARTITION BY Student, Category ORDER BY Score DESC) SeqInStudentCategory 
    FROM WeightedScores
)

现在我们只对SeqInStudentCategory为1的行感兴趣.只考虑这些行,让我们按学生的分数对它们进行排序,然后对这些行进行编号:

-- within the preceding WITH
, Numbered2 ( Question, Student, Category, Score, SeqInStudent ) AS
(
    SELECT 
        Question, Student, Category, Score
        , ROW_NUMBER() OVER (PARTITION BY Student ORDER BY Score DESC) SeqInStudent
    FROM
        Numbered1
    WHERE
        SeqInStudentCategory = 1
)

现在我们只对SeqInStudent最多的行感兴趣.让我们把它们拉出来,这样我们就知道要包含它(并将它从简单的排序中排除,我们将用它来构成剩下的七行):

-- within the preceding WITH
, TopInCat ( Question, Student, Category, Score, SeqInStudent ) AS
(
     SELECT Question, Student, Category, Score, SeqInStudent FROM Numbered2 WHERE SeqInStudent <= 3
)

现在我们为每个学生提供三个顶级类别的问题.我们现在需要通过分数来识别和排序每个学生的不是顶级问题:

-- within the preceding WITH
, NotTopInCat ( Question, Student, Category, Score, SeqInStudent ) AS
(
    SELECT
        Question, Student, Category, Score
        , ROW_NUMBER() OVER (PARTITION BY Student ORDER BY Score DESC) SeqInStudent
    FROM
        WeightedScores WS
    WHERE
        NOT EXISTS ( SELECT 1 FROM TopInCat T WHERE T.Question = WS.Question AND T.Student = WS.Student )
)

最后,我们将TopInCat与NotTopInCat结合起来,对NotTopInCat.SeqInStudent应用适当的偏移量和限制 – 我们需要将3添加到原始值,然后取前7(即10 – 3):

-- within the preceding WITH
, Combined ( Question, Student, Category, Score, CombinedSeq ) AS
(
    SELECT
        Question, Student, Category, Score, SeqInStudent AS CombinedSeq
    FROM
        TopInCat
    UNION
    SELECT
        Question, Student, Category, Score, SeqInStudent + 3 AS CombinedSeq
    FROM
        NotTopInCat
    WHERE
        SeqInStudent <= 10 - 3
)

要获得我们的最终结果:

SELECT * FROM Combined ORDER BY Student, CombinedSeq
;

你可以看到结果on sqlfiddle.

请注意,在这里我假设每个学生总是会得到至少三个类别的答案.此外,最终输出没有TopInCat列,但希望你会看到如果你想要它如何重新获得它.

此外,“(问题的#和类别的#将最终变量)”在这里处理应该相对简单.但请注意我的假设(在这种情况下)每个学生的答案肯定会出现3个类别.

点赞