根据另一行中的条件构建总计

Building totals based on condition in another row

真的很难理解这样做的最佳方法...

我有一个table的数据

**StudentID  AssessmentCode  ResultGroup    Result**
  46933          12ENG        IBLevel          HL
  46933          12ENG        Mark             6
  46933          12ECO        IBLevel          HL
  46933          12ECO        Mark             5
  46933          12GEO        IBLevel          SL
  46933          12GEO        Mark             6
  46933          12LAN        IBLevel          HL
  46933          12LAN        Mark             4
  46933          12PED        IBLevel          SL
  46933          12PED        Mark             5
  46933          12SCI        IBLevel          SL
  46933          12SCI        Mark             3
  67767          12FRE        IBLevel          HL
  67767          12FRE        Mark             4
  67767          12MAT        IBLevel          SL
  67767          12MAT        Mark             5
  and so on...

不幸的是,结果列包含 2 位不同的信息。学生的水平(HL = 高水平;SL = 标准水平),然后是该科目在该水平的成绩。请注意,对于每个学生,每个学生的每个科目都会生成 2 行,一行包含 IBLevel,下一行包含该级别的结果。

如何重新排列数据以获得类似

的内容
StudentID    HLResult    SLResult    TotalResult   CountofHL  CountofSL
  46933         15          14           29            3          3
  67767         13          10           23            4          2

所以每个学生都有一行数据,其中包含 HL、SL 的总计,以及 HL 和 SL 科目的数量。正如我所说,真的不确定解决这个问题的最佳方法。最后,我还想扩展它以获得一些列,这些列根据结果给出一些警告消息,例如 TotalResult 必须大于 24,所以我喜欢一个列,它只是 returns 是否有是否实现...

StudentID  HLResult  SLResult  TotalResult CountofHL CountofSL MoreThan24
  46933       15        14         29          3        3         True
  67767       13        10         23          4        2         False

任何帮助将不胜感激...

您的 table 似乎存在一些严重的规范化问题。您必须先在 AssessmentCode 上执行 INNER JOIN

SELECT t1.StudentID, t1.AssessmentCode, 
       t1.Result AS Level, CAST(t2.Result AS INT) AS Mark 
FROM (
   SELECT StudentID, AssessmentCode, Result
   FROM mytable
   WHERE ResultGroup = 'IBLevel' ) AS t1
INNER JOIN (
   SELECT StudentID, AssessmentCode, Result
   FROM mytable
   WHERE ResultGroup = 'Mark' ) AS t2
ON t1.StudentID = t2.StudentID AND t1.AssessmentCode = t2.AssessmentCode

AssessmentCode 获得一行。

输出:

StudentID   AssessmentCode  Level   Mark
-----------------------------------------
46933       12ENG           HL      6
46933       12ECO           HL      5
46933       12GEO           SL      6
46933       12LAN           HL      4
46933       12PED           SL      5
46933       12SCI           SL      3
67767       12FRE           HL      4
67767       12MAT           SL      5

您现在可以将上述查询包装在 CTE 中并执行 条件聚合 以获得所需的结果:

;WITH CTE AS (
 ... above query here
)
SELECT StudentID, 
       SUM(CASE WHEN Level = 'HL' THEN Mark ELSE 0 END) AS HLResult,
       SUM(CASE WHEN Level = 'SL' THEN Mark ELSE 0 END) AS SLResult,
       SUM(Mark) AS TotalResult,
       COUNT(CASE WHEN Level = 'HL' THEN 1 END) AS CountofHL,
       COUNT(CASE WHEN Level = 'SL' THEN 1 END) AS CountofSL,
       CASE WHEN SUM(Mark) > 24 THEN 'True'
            ELSE 'False'
       END AS MoreThan24
FROM CTE
GROUP BY StudentID  

输出:

StudentID   HLResult    SLResult    TotalResult CountofHL   CountofSL   MoreThan24
46933       15          14          29          3           3           True
67767       4           5           9           1           1           False

Demo here

你的我的版本Table

DECLARE @yourTable TABLE
(
    StudentID       INT,
    AssessmentCode  CHAR(5),
    ResultGroup     VARCHAR(10),
    Result          VARCHAR(5)
)

INSERT INTO @yourTable
VALUES  (46933,'12ENG','IBLevel','HL'),
        (46933,'12ENG','Mark','6'),
        (46933,'12ECO','IBLevel','HL'),
        (46933,'12ECO','Mark','5'),
        (46933,'12GEO','IBLevel','SL'),
        (46933,'12GEO','Mark','6'),
        (46933,'12LAN','IBLevel','HL'),
        (46933,'12LAN','Mark','4'),
        (46933,'12PED','IBLevel','SL'),
        (46933,'12PED','Mark','5'),
        (46933,'12SCI','IBLevel','SL'),
        (46933,'12SCI','Mark','3'),
        (67767,'12FRE','IBLevel','HL'),
        (67767,'12FRE','Mark','4'),
        (67767,'12MAT','IBLevel','SL'),
        (67767,'12MAT','Mark','5');

实际查询

WITH CTE_ResultValue
AS
(
    SELECT  StudentID,
            AssessmentCode,
            ResultGroup,
            CAST(Result AS INT) AS ResultValue
    FROM @yourTable
    WHERE ISNUMERIC(Result) = 1
),
CTE_IBLevel
AS
(
    SELECT  StudentID,
        AssessmentCode,
        Result AS IBLevel
    FROM @yourTable
    WHERE ISNUMERIC(Result) = 0
),
CTE_Normalized
AS
(
    SELECT  A.StudentID,
            A.AssessmentCode,
            A.ResultGroup,
            A.ResultValue,
            B.IBLevel
    FROM CTE_ResultValue    AS A
    INNER JOIN CTE_IBLevel  AS B
    ON      A.StudentID = B.StudentID
        AND A.AssessmentCode = B.AssessmentCode
)

SELECT  [StudentID],
        [HLResult]      = SUM(CASE WHEN IBLevel = 'HL' THEN ResultValue END),
        [SLResult]      = SUM(CASE WHEN IBLevel = 'SL' THEN ResultValue END),
        [TotalResult]   = SUM(ResultValue),
        [CountOfHL]     = SUM(CASE WHEN IBLevel = 'HL' THEN 1 END),
        [CountOfSL]     = SUM(CASE WHEN IBLevel = 'SL' THEN 1 END)
FROM CTE_Normalized
GROUP BY StudentID

规范化

您的 table 非常需要规范化。如果您可以更改它,最小的更改将如下所示:

CREATE TABLE dbo.NormalizedTable
(
    StudentID       INT,
    AssessmentCode  CHAR(5),
    ResultGroup     VARCHAR(25),
    ResultValue     SMALLINT, --smallint range should be plenty. It can store values from -32,768 to 32,767
    IBLevel         CHAR(2)
)
INSERT INTO dbo.NormalizedTable
SELECT *
FROM CTE_Normalized

如果您无法更改数据的结构方式,我建议您从我的 CTE_normalized

创建一个视图
CREATE VIEW vw_normalizedTable
AS
WITH CTE_ResultValue
AS
(
    SELECT  StudentID,
            AssessmentCode,
            ResultGroup,
            CAST(Result AS INT) AS ResultValue
    FROM @yourTable
    WHERE ISNUMERIC(Result) = 1
),
CTE_IBLevel
AS
(
    SELECT  StudentID,
        AssessmentCode,
        Result AS IBLevel
    FROM @yourTable
    WHERE ISNUMERIC(Result) = 0
),

SELECT  A.StudentID,
        A.AssessmentCode,
        A.ResultGroup,
        A.ResultValue,
        B.IBLevel
FROM CTE_ResultValue    AS A
INNER JOIN CTE_IBLevel  AS B
ON      A.StudentID = B.StudentID
    AND A.AssessmentCode = B.AssessmentCode
GO

版本 1:

SELECT t1.StudentID, 
SUM(CASE WHEN t1.Result = 'HL' THEN t2.Result ELSE 0 END) HLResult,
SUM(CASE WHEN t1.Result = 'SL' THEN t2.Result ELSE 0 END) SLResult,
SUM(CAST(t2.Result AS INT)) TotalResult,
SUM(CASE WHEN t1.Result = 'HL' THEN 1 ELSE 0 END) CountofHL,
SUM(CASE WHEN t1.Result = 'SL' THEN 1 ELSE 0 END) CountofSL,
CASE WHEN SUM(CAST(t2.Result AS INT)) > 24 THEN 'True' ELSE 'False' END MoreThan24    
FROM @t t1
JOIN @t t2 ON t1.StudentID = t2.StudentID AND 
              t1.AssessmentCode = t2.AssessmentCode AND 
              t1.ResultGroup = 'IBLevel' AND 
              t2.ResultGroup = 'Mark'
GROUP BY t1.StudentID

版本 2:

WITH cte1 AS(
SELECT *, ROW_NUMBER() OVER(PARTITION BY StudentID, AssessmentCode 
          ORDER BY CASE WHEN ResultGroup = 'IBLevel' THEN 1 ELSE 2 END) AS rn FROM @t),
cte2 AS(SELECT StudentID, 
               AssessmentCode, 
               SUM(CASE WHEN Result = 'HL' THEN 1 ELSE 0 END) HL, 
               SUM(CASE WHEN Result = 'SL' THEN 1 ELSE 0 END) SL, 
               MAX(CASE WHEN rn = 2 THEN Result END) R
        FROM cte1
        GROUP BY StudentID, AssessmentCode)
SELECT StudentID, 
       SUM(hl*R) HLResult, 
       SUM(sl*R) SLResult, 
       SUM((hl + sl)*r) TotalResult, 
       SUM(hl) CountofHL, 
       SUM(sl) CountofSL,
       CASE WHEN SUM((hl + sl)*r) > 24 THEN 'True' ELSE 'False' END MoreThan24    
FROM cte2
GROUP BY StudentID

输出:

StudentID   HLResult    SLResult    TotalResult CountofHL   CountofSL   MoreThan24
46933       15          14          29          3           3           True
67767       4           5           9           1           1           False

只需将 @t 替换为您的 table。