sql >> データベース >  >> RDS >> Sqlserver

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
    

    これは、少なくともあなたが求めたものに近いはずです。これをピボットに変換するには動的 SQL が必要になります。SQL Server では列にピボットされる実際の値を指定する必要があるためです。

    質問を相互結合し、これらの各質問参照からの結果を、それぞれ行の値と列の値の単一の質問に制限します。次に、オプション値をそれぞれの質問参照に結合します。ユーザーがすべての質問に応答しなかった場合に備えて、回答に LEFT JOIN を使用します。そして、各ユーザーの行の質問と列の質問を一致させるために、UserID で回答を結合します。オプション テキストの MIN は、表示されているシーケンスと一致するように OptionID でグループ化および順序付けされているためです。

    編集:これは SQLFiddle です。

    Entity-Attribute-Value デザイン パターンを使用しているため、クエリは複雑です。かなりの数の SQL Server 専門家が、このパターンに問題があり、可能であれば避けるべきだと考えています。たとえば、https:/ を参照してください。 /www.simple-talk.com/sql/t-sql-programming/avoiding-the-eav-of-destruction/ .

    EDIT 2:あなたが私の答えを受け入れたので、ここに動的 SQL ピボット ソリューションがあります:) SQLフィドル

    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
    


    1. 文字のn番目のインスタンスのみを置き換える

    2. TO_CHARを使用したOracleでの数値フォーマット

    3. SQLiteでテーブルを作成する

    4. INSERT INTO ... ONDUPLICATEUPDATEすべての値