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

时间:2015-06-12 13:27:39

标签: tsql pivot

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

我有一张数据表

**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,所以我想要一个只返回是否已实现的列...

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

非常感谢任何帮助......

3 个答案:

答案 0 :(得分:0)

您的表似乎有一些严重的规范化问题。您必须首先在INNER JOIN执行AssessmentCode

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

答案 1 :(得分:0)

我的桌子版本

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

正常化

你的桌子非常需要规范化。如果你可以改变它,那么最小的变化将是这样的:

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

答案 2 :(得分:0)

<强>版本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替换为您的表格。