2017-03-08 1 views
1

J'utilise SQL Server 2008 et j'essaie d'écrire une requête qui divise les colonnes en lignes individuelles. Je tire des données de compte et ai besoin de le transformer en scores individuels.SQL: UN-PIVOT et séparé par score individuel

Exemple:
5 étudiants répondent « toujours » et une réponse « toujours » = 3 points;
4 élèves de répondre « habituellement » et la réponse de « généralement » = 2 points

Au lieu d'avoir un champ nommé « toujours » avec un nombre de 5 et un champ nommé « habituellement » avec un nombre de 4, je le ferais J'aime avoir un champ nommé 'Score' avec 5 lignes de 3 et 4 lignes de 2.

J'ai commencé ma requête en utilisant un UNPIVOT, cependant, il ne divise pas les données comme décrit. J'ai inclus des exemples de données et mes résultats souhaités ci-dessous. Toute aide serait appréciée.

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

données Exemple:

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) 

Requête:

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 

Résultats attendus: pour la 1ère 2 rangs

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 

Répondre

1

Avec l'aide d'une croix APPLIQUER et une table de pointage ad hoc

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' 

Retours

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 
+0

Merci pour l'aide, votre suggestion fonctionne pour mon ensemble d'échantillons de données. Pouvez-vous expliquer cela "JOIN (SELECT TOP 100 N = ROW_NUMBER() OVER (ORDER BY Nombre) FROM master..spt_values)"? Je n'ai jamais vu cette table utilisée et je ne comprends pas pourquoi vous l'avez utilisé ou sélectionné le top 100. – JBritton

+1

@JBritton Juste en créant un tableau ad-hoc de 100 enregistrements. Cela permettra "l'expansion" de votre jeu d'enregistrements. –

+1

@JBritton Le Top 100 était une valeur arbitraire. Si vous ne verrez jamais plus de 10 réponses, alors faites-en Top 10. Cela ne fait pas de mal d'avoir une valeur plus grande. La sous-requête est résolue une fois –

0

Si vous avez un nombre gérable de colonnes à unpivot, je fais généralement juste des requêtes séparées pour chacune, et combinées avec un UNION ALL.

Voici l'idée générale:

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

UNION ALL 

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

utilisant cross apply (values...) à UNPIVOT vos données, un tableau de chiffres pour 1-9, et une table de points, nous pouvons faire quelque chose comme ceci:

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 Démo: http://rextester.com/GQCN45867

retours:

+----------+---------+------------+-------+-----------+ 
| 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 | 
+----------+---------+------------+-------+-----------+