Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Query SQL a schede incrociate

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

Questo dovrebbe essere almeno vicino a quello che hai chiesto. Trasformarlo in un pivot richiederà un SQL dinamico poiché SQL Server richiede di specificare il valore effettivo che verrà convertito in una colonna.

Uniamo in modo incrociato le domande e limitiamo i risultati di ciascuno di quei riferimenti alle domande alla singola domanda rispettivamente per i valori di riga e di colonna. Quindi uniamo i valori delle opzioni al rispettivo riferimento alla domanda. Usiamo LEFT JOIN per le risposte nel caso l'utente non abbia risposto a tutte le domande. E uniamo le risposte per UserID in modo da abbinare la domanda di riga e la domanda di colonna per ciascun utente. Il MIN sul testo dell'opzione è perché abbiamo raggruppato e ordinato per OptionID in modo che corrisponda alla sequenza mostrata.

EDIT:ecco un SQLFiddle

Per quel che vale, la tua query è complicata perché stai usando il modello di progettazione Entity-Attribute-Value. Numerosi esperti di SQL Server considerano questo modello problematico e da evitare, se possibile. Ad esempio, vedere https:/ /www.simple-talk.com/sql/t-sql-programming/avoiding-the-eav-of-destruction/ .

EDIT 2:Dal momento che hai accettato la mia risposta, ecco la soluzione pivot SQL dinamica :) 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