Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Consulta de guia cruzada SQL

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

Isso deve ser pelo menos próximo do que você pediu. Transformar isso em um pivô exigirá SQL dinâmico, pois o SQL Server exige que você especifique o valor real que será dinamizado em uma coluna.

Unimos as perguntas e limitamos os resultados de cada uma dessas referências de pergunta à pergunta única para os valores de linha e valores de coluna, respectivamente. Em seguida, juntamos os valores das opções à respectiva referência da pergunta. Usamos LEFT JOIN para as respostas caso o usuário não tenha respondido a todas as perguntas. E juntamos as respostas por UserID para que correspondamos à pergunta da linha e à pergunta da coluna para cada usuário. O MIN no texto da opção é porque agrupamos e ordenamos por OptionID para corresponder ao seu sequenciamento mostrado.

EDIT:Aqui está um SQLFiddle

Para o que vale a pena, sua consulta é complicada porque você está usando o padrão de design Entity-Attribute-Value. Alguns especialistas em SQL Server consideram esse padrão problemático e a ser evitado, se possível. Por exemplo, veja https:/ /www.simple-talk.com/sql/t-sql-programming/avoiding-the-eav-of-destruction/ .

EDIT 2:Desde que você aceitou minha resposta, aqui está a solução dinâmica do SQL dinâmico :) 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