SQL:UN-PIVOT 并按个人得分分开

SQL: UN-PIVOT and separate by individual score

我正在使用 SQL Server 2008 并尝试编写一个将列拆分为单独行的查询。我正在提取计数数据,需要将其转换为个人分数。

示例:
5个同学回答“总是”,回答“总是”=3分;
4 个学生回答“通常”,回答“通常”= 2 分

我不想有一个名为“always”且计数为 5 的字段和一个名为“usually”且计数为 4 的字段,我希望有一个名为“Score”的字段有 5 行,每行 3 行和 4 行2 行。

我已经使用 UNPIVOT 开始我的查询,但是,它没有按照描述拆分数据。我在下面包含了样本数据和我想要的结果。任何帮助,将不胜感激。

Always = 3 points  
Usually = 2 points      
Sometimes = 1 points    
Never = 0 points 

示例数据:

CREATE TABLE #TEST(QUESTION VARCHAR(15), STUDENT VARCHAR(15), STARTDATE DATE, ALWAYS INT, USUALLY INT, SOMETIMES INT, NEVER INT)

INSERT #TEST(QUESTION, STUDENT, STARTDATE, ALWAYS, USUALLY, SOMETIMES, NEVER)
VALUES
('A','BOB','01/01/2016',2,1,1,2),
('A','BOB','03/01/2016',3,1,1,0),
('A','JIM','01/01/2016',2,1,2,0),
('A','JIM','03/01/2016',4,1,0,0),
('BB','BOB','03/01/2016',2,1,1,2),
('BB','BOB','07/01/2016',3,1,1,0),
('BB','JIM','03/01/2016',2,1,2,0),
('BB','JIM','07/01/2016',4,1,0,0)  

查询:

WITH A AS (
    SELECT *
    FROM #TEST
    --WHERE 
    --  QUESTION = 'A' 
    --AND STUDENT IN ('BOB','JIM')
    --AND STARTDATE = '2016-01-01'
)   
SELECT QUESTION, STUDENT, STARTDATE, SCORE
FROM 
    (   SELECT QUESTION, STUDENT, STARTDATE, ALWAYS, USUALLY, SOMETIMES, NEVER
        FROM A
    ) P
UNPIVOT
    ( SCORE FOR Z IN (ALWAYS, USUALLY, SOMETIMES, NEVER)
    ) AS unpvt  

预期结果:第 1 2 行

QUESTION|STUDENT|STARTDATE|SCORE|
--------+-------+---------+-----+
A       |BOB    |1/1/2016 |3    |--ALWAYS
A       |BOB    |1/1/2016 |3    |--ALWAYS
A       |BOB    |1/1/2016 |2    |--USUALLY
A       |BOB    |1/1/2016 |1    |--SOMETIMES
A       |BOB    |1/1/2016 |0    |--NEVER
A       |BOB    |1/1/2016 |0    |--NEVER
A       |BOB    |3/1/2016 |3    |--ALWAYS
A       |BOB    |3/1/2016 |3    |--ALWAYS
A       |BOB    |3/1/2016 |3    |--ALWAYS
A       |BOB    |3/1/2016 |2    |--USUALLY
A       |BOB    |3/1/2016 |1    |--SOMETIMES

如果要逆透视的列数量可控,我通常只对每个列进行单独查询,然后结合 UNION ALL

大致思路如下:

SELECT Question, Student, StartDate, Always AS Score
FROM #TEST
WHERE ...

UNION ALL

SELECT Question, Student, StartDate, Usually AS Score
FROM #TEST
WHERE ...

在 CROSS APPLY 和临时计数的帮助下 table

Select A.Question
      ,A.Student
      ,A.StartDate
      ,B.Score
 From  #Test A
 Cross Apply ( values (Always,3)
                     ,(Usually,2)
                     ,(Sometimes,1)
                     ,(Never,0) 
              ) B(Cnt,Score)
 Join (Select Top 100 N=Row_Number() Over (Order By Number) From master..spt_values ) C
   on (C.N <= B.Cnt)
 Where Student='Bob' and question ='A'

Returns

Question    Student StartDate   Score
A           BOB     2016-01-01  3
A           BOB     2016-01-01  3
A           BOB     2016-01-01  2
A           BOB     2016-01-01  1
A           BOB     2016-01-01  0
A           BOB     2016-01-01  0
A           BOB     2016-03-01  3
A           BOB     2016-03-01  3
A           BOB     2016-03-01  3
A           BOB     2016-03-01  2
A           BOB     2016-03-01  1

使用 cross apply (values...) 逆透视你的数据,一个数字 table 代表 1-9,一个点 table,我们可以这样做:

with a as (
  select *
  from #test
  where question = 'A' 
    and student = 'bob'
    --and student in ('bob','jim')
    --and startdate = '20160101'
)
, points as (
  select Answer, Points
  from (values ('Always',3),('Usually',2),('Sometimes',1),('Never',0)
    ) p (Answer,Points)
)
, numbers as (
  select n 
  from (values(1),(2),(3),(4),(5),(6),(7),(8),(9)
    ) t(n)
)
, unp as (
  select 
      a.question
    , a.student
    , StartDate=convert(varchar(10),a.startdate,120)
    , x.AnswerCount
    , x.Answer
  from a
    cross apply (
      values ([Always],'Always')
        , ([Usually],'Usually')
        , ([Sometimes],'Sometimes')
        , ([Never],'Never')
      ) x (AnswerCount,Answer)
)
select 
    unp.question
  , unp.student
  , unp.startdate
  , score = p.points
  , unp.answer
  from unp
    inner join numbers n on n.n<=unp.AnswerCount
    inner join points p on unp.answer=p.answer

rextester 演示:http://rextester.com/GQCN45867

returns:

+----------+---------+------------+-------+-----------+
| question | student | startdate  | score |  answer   |
+----------+---------+------------+-------+-----------+
| A        | bob     | 2016-01-01 |     3 | Always    |
| A        | bob     | 2016-01-01 |     3 | Always    |
| A        | bob     | 2016-01-01 |     2 | Usually   |
| A        | bob     | 2016-01-01 |     1 | Sometimes |
| A        | bob     | 2016-01-01 |     0 | Never     |
| A        | bob     | 2016-01-01 |     0 | Never     |
| A        | bob     | 2016-01-03 |     3 | Always    |
| A        | bob     | 2016-01-03 |     3 | Always    |
| A        | bob     | 2016-01-03 |     3 | Always    |
| A        | bob     | 2016-01-03 |     2 | Usually   |
| A        | bob     | 2016-01-03 |     1 | Sometimes |
+----------+---------+------------+-------+-----------+