Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

SQL-Kreuztabellenabfrage

SELECT MIN(ro.OptionText) RowOptionText, MIN(co.OptionText) RowOptionText, COUNT(ca.AnswerID) AnswerCount
FROM tblQuestions rq 
CROSS JOIN tblQuestions cq 
JOIN tblOptions ro ON rq.QuestionID = ro.QuestionID
JOIN tblOptions co ON cq.QuestionID = co.QuestionID
LEFT JOIN tblAnswers ra ON ra.OptionID = ro.OptionID
LEFT JOIN tblAnswers ca ON ca.OptionID = co.OptionID AND ca.UserID = ra.UserID
WHERE rq.questionText = 'Gender'
AND cq.questionText = 'How happy are you?'
GROUP BY ro.OptionID, co.OptionID
ORDER BY ro.OptionID, co.OptionID

Dies sollte mindestens dem entsprechen, wonach Sie gefragt haben. Um dies in einen Pivot umzuwandeln, ist dynamisches SQL erforderlich, da SQL Server von Ihnen verlangt, den tatsächlichen Wert anzugeben, der in eine Spalte geschwenkt wird.

Wir verbinden die Fragen und beschränken die Ergebnisse von jeder dieser Fragenreferenzen auf die einzelne Frage für die Zeilenwerte bzw. Spaltenwerte. Dann verbinden wir die Optionswerte mit dem jeweiligen Fragenbezug. Wir verwenden LEFT JOIN für die Antworten, falls der Benutzer nicht auf alle Fragen geantwortet hat. Und wir verbinden die Antworten nach Benutzer-ID, sodass wir die Zeilenfrage und die Spaltenfrage für jeden Benutzer abgleichen. Die MIN im Optionstext ist darauf zurückzuführen, dass wir nach OptionID gruppiert und bestellt haben, um Ihrer angezeigten Sequenzierung zu entsprechen.

EDIT:Hier ist ein SQLFiddle

Für das, was es wert ist, ist Ihre Abfrage kompliziert, da Sie das Entitäts-Attribut-Wert-Entwurfsmuster verwenden. Nicht wenige SQL Server-Experten halten dieses Muster für problematisch und sollten möglichst vermieden werden. Siehe zum Beispiel https:/ /www.simple-talk.com/sql/t-sql-programming/avoiding-the-eav-of-destruction/ .

EDIT 2:Da Sie meine Antwort akzeptiert haben, hier ist die dynamische SQL-Pivot-Lösung :) SQLFiddle

DECLARE @SqlCmd NVARCHAR(MAX)

SELECT @SqlCmd = N'SELECT RowOptionText, ' + STUFF(
    (SELECT ', ' + QUOTENAME(o.OptionID) + ' AS ' + QUOTENAME(o.OptionText)
    FROM tblOptions o 
    WHERE o.QuestionID = cq.QuestionID
    FOR XML PATH ('')), 1, 2, '') + ', RowTotal AS [Row Total]
FROM (
    SELECT ro.OptionID RowOptionID, ro.OptionText RowOptionText, co.OptionID ColOptionID,
       ca.UserID, COUNT(ca.UserID) OVER (PARTITION BY ra.OptionID) AS RowTotal
    FROM tblOptions ro
    JOIN tblOptions co ON ro.QuestionID = ' + CAST(rq.QuestionID AS VARCHAR(10)) + 
    ' AND co.QuestionID = ' + CAST(cq.QuestionID AS VARCHAR(10)) + '
    LEFT JOIN tblAnswers ra ON ra.OptionID = ro.OptionID
    LEFT JOIN tblAnswers ca ON ca.OptionID = co.OptionID AND ca.UserID = ra.UserID
    UNION ALL 
    SELECT 999999, ''Column Total'' RowOptionText, co.OptionID ColOptionID,
       ca.UserID, COUNT(ca.UserID) OVER () AS RowTotal
    FROM tblOptions ro
    JOIN tblOptions co ON ro.QuestionID = ' + CAST(rq.QuestionID AS VARCHAR(10)) + 
    ' AND co.QuestionID = ' + CAST(cq.QuestionID AS VARCHAR(10)) + '
    LEFT JOIN tblAnswers ra ON ra.OptionID = ro.OptionID
    LEFT JOIN tblAnswers ca ON ca.OptionID = co.OptionID AND ca.UserID = ra.UserID
) t
PIVOT (COUNT(UserID) FOR ColOptionID IN (' + STUFF(
    (SELECT ', ' + QUOTENAME(o.OptionID) 
    FROM tblOptions o 
    WHERE o.QuestionID = cq.QuestionID
    FOR XML PATH ('')), 1, 2, '') + ')) p
ORDER BY RowOptionID'
FROM tblQuestions rq 
CROSS JOIN tblQuestions cq 
WHERE rq.questionText = 'Gender' 
AND cq.questionText = 'How happy are you?'

EXEC sp_executesql @SqlCmd