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 |
+----------+---------+------------+-------+-----------+
我正在使用 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 |
+----------+---------+------------+-------+-----------+