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
这应该是在最接近你要求的。将此转换为数据透视表将需要动态SQL,因为SQL Server要求您指定将被旋转到列中的实际值。
我们交叉连接问题,并分别将这些问题引用的结果限制为单个问题的行值和列值。然后我们将选项值加入相应的问题参考。如果用户没有回答所有问题,我们使用LEFT JOIN作为答案。我们通过UserID加入答案,以便我们匹配每个用户的行问题和列问题。选项文本上的MIN是因为我们按OptionID进行了分组和排序,以匹配显示的排序。
编辑:这里有一个SQLFiddle
对于它的价值,你的查询是因为你使用的是实体 - 属性 - 值设计模式复杂。不少SQL Server专家认为该模式存在问题,如果可能的话应避免。例如见https://www.simple-talk.com/sql/t-sql-programming/avoiding-the-eav-of-destruction/。
编辑2:既然你接受了我的答案,这里的动态SQL支点的解决方案:) 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
您是否阅读过“SQL PIVOT”? – 2014-08-29 14:43:45
您可以使用数据透视查询,或者如果您在所需输出中有一组固定的列,则可以使用case语句。或者,更好的是,您可以使用报告工具来处理您的演示文稿。 – Andrew 2014-08-29 14:45:03
我已经查看了SQL PIVOT,但无法弄清楚如何将它用于我的场景。不幸的是,使用第三方报告工具不是一种选择。 – Aki 2014-08-29 14:47:44