NULL не разваливается в стержне (возможна проблема JOIN) - PullRequest
0 голосов
/ 14 апреля 2020

У меня есть четыре таблицы:

Survey
------
Id | ClientId | SurveyDate

SurveyQuestion
--------------
Id | QuestionText

SurveyAnswer
--------------
Id | AnswerText | AnswerScore

SurveyResponse
---------------
Id | SurveyId | QuestionId | AnswerId

В таблице вопросов в настоящее время есть 6 вопросов с возможностью их добавления позже. Таблица ответов содержит только строки для опроса, на который был дан ответ.

Моя конечная цель - объединить опросы с ответами, затем с ответами и затем развернуть все вопросы.

Пока у меня есть следующий код:

DECLARE @HighScore INT = (SELECT COUNT(*) FROM SurveyQuestion)
    DECLARE @LowScore INT = 0 - @HighScore

    DECLARE @cols NVARCHAR (MAX)

    SELECT @cols = COALESCE (@cols + ',[' + a.QuestionText + ']', 
                    '[' + a.QuestionText + ']')
                    FROM (SELECT DISTINCT QuestionText, SortOrder FROM SurveyQuestion) a
                    ORDER BY SortOrder

    DECLARE @NulltoZeroCols NVARCHAR(MAX)

    SET @NullToZeroCols = SUBSTRING((SELECT ',ISNULL(['+ a.QuestionText +'],NULL) AS ['+ a.QuestionText +']' 
    FROM (SELECT DISTINCT QuestionText, SortOrder FROM SurveyQuestion) a
                    ORDER BY SortOrder FOR XML PATH('')),2,8000)

    DECLARE @query NVARCHAR(MAX)
    SET @query = '
    SELECT [ClientId], [SurveyDate],'+ @NulltoZeroCols +', [QuestionsAnswered], [TotalScore], CONVERT(DECIMAL(10,2),[QuestionsAnswered])/'+CONVERT(NVARCHAR, @HighScore)+'*[TotalScore] AS [AdjustedScore] FROM 
                    (
                    SELECT CS.Id AS ClientId, SurveyDate, SurveyId, QuestionText, AnswerScore, AnswerText, COUNT(*) OVER (PARTITION BY ClientId, SurveyDate) AS QuestionsAnswered, SUM(AnswerScore) OVER (PARTITION BY ClientId, SurveyDate) AS TotalScore
                    FROM Survey CS
                    INNER JOIN SurveyResponse CSR
                    ON CS.Id = CSR.SurveyId
                    INNER JOIN SurveyQuestion CSQ
                    ON CSR.QuestionId = CSQ.Id
                    INNER JOIN SurveyAnswer CSA
                    ON CSR.AnswerId = CSA.Id
                    ) x
                    PIVOT
                (  
                    MAX(x.AnswerText)
                    FOR  [QuestionText] IN (' + @cols + ')
                ) p
                ORDER BY [SurveyDate] DESC;' 

    EXEC SP_EXECUTESQL @query

Мой ожидаемый вывод:

ClientId    SurveyDate  'Q1Text' 'Q2Text' 'Q3Text' 'Q4Text' 'Q5Text' 'Q6Text'   QuestionsAnswered   TotalScore  AdjustedScore
124 2020-04-14  No  No  No  No  No  No  6   -6  -6.000000
134 2020-04-14  No  No  No  No  Yes Yes 6   -2  -2.000000
137 2020-04-14  Yes No  No  No  Don't Know No   6   -3  -3.000000
17  2018-11-01  Yes NULL    Yes No  NULL    NULL    3   1   0.500000

Но мой фактический вывод не сворачивает значения NULL.

ClientId    SurveyDate  'Q1Text' 'Q2Text' 'Q3Text' 'Q4Text' 'Q5Text' 'Q6Text'   QuestionsAnswered   TotalScore  AdjustedScore
124 2020-04-14  No  No  No  No  No  No  6   -6  -6.000000
134 2020-04-14  No  No  No  No  NULL    NULL    6   -2  -2.000000
134 2020-04-14  NULL    NULL    NULL    NULL    Yes Yes 6   -2  -2.000000
137 2020-04-14  NULL    No  No  No  NULL    No  6   -3  -3.000000
137 2020-04-14  NULL    NULL    NULL    NULL    Don't Know  NULL    6   -3  -3.000000
137 2020-04-14  Yes NULL    NULL    NULL    NULL    NULL    6   -3  -3.000000
17  2018-11-01  NULL    NULL    NULL    No  NULL    NULL    3   1   0.500000
17  2018-11-01  Yes NULL    Yes NULL    NULL    NULL    3   1   0.500000

Я считаю, что это потому, что вопросы не решаются до разворота. Я попытался соединить вопросы с ответами LEFT и RIGHT, но сначала безрезультатно (значения NULL не отображаются).

Возможно, я где-то что-то усложнил, но не могу увидеть лес за деревьями ! Любая помощь будет принята с благодарностью.

РЕДАКТИРОВАТЬ: согласно Габриэлю

Вывод подзапроса:

ClientId    SurveyDate  SurveyId    QuestionText    AnswerScore AnswerText  QuestionsAnswered   TotalScore
17  2018-11-01  17  Q1Text  1   Yes 3   1
17  2018-11-01  17  Q3Text  1   Yes 3   1
17  2018-11-01  17  Q4Text  -1  No  3   1
134 2020-04-14  134 Q1Text  -1  No  6   -2
134 2020-04-14  134 Q2Text  -1  No  6   -2
134 2020-04-14  134 Q3Text  -1  No  6   -2
134 2020-04-14  134 Q4Text  -1  No  6   -2
134 2020-04-14  134 Q5Text  1   Yes 6   -2
134 2020-04-14  134 Q6Text  1   Yes 6   -2
124 2020-04-14  124 Q1Text  -1  No  6   -6
124 2020-04-14  124 Q2Text  -1  No  6   -6
124 2020-04-14  124 Q3Text  -1  No  6   -6
124 2020-04-14  124 Q4Text  -1  No  6   -6
124 2020-04-14  124 Q5Text  -1  No  6   -6
124 2020-04-14  124 Q6Text  -1  No  6   -6
137 2020-04-14  137 Q1Text  1   Yes 6   -3
137 2020-04-14  137 Q2Text  -1  No  6   -3
137 2020-04-14  137 Q3Text  -1  No  6   -3
137 2020-04-14  137 Q4Text  -1  No  6   -3
137 2020-04-14  137 Q5Text  0   Don't Know  6   -3
137 2020-04-14  137 Q6Text  -1  No  6   -3

1 Ответ

1 голос
/ 14 апреля 2020

Извините, мой предыдущий ответ был неверным. Все, что вам нужно сделать, это удалить AnswerScore из подзапроса 'x', вы все равно его не используете.

DECLARE @HighScore INT = (SELECT COUNT(*) FROM SurveyQuestion)
DECLARE @LowScore INT = 0 - @HighScore

DECLARE @cols NVARCHAR (MAX)

SELECT @cols = COALESCE (@cols + ',[' + a.QuestionText + ']', 
                '[' + a.QuestionText + ']')
                FROM (SELECT DISTINCT QuestionText, SortOrder FROM SurveyQuestion) a

DECLARE @NulltoZeroCols NVARCHAR(MAX)

SET @NullToZeroCols = SUBSTRING((SELECT ',ISNULL(['+ a.QuestionText +'],NULL) AS ['+ a.QuestionText +']' 
FROM (SELECT DISTINCT QuestionText, SortOrder FROM SurveyQuestion) a
                ORDER BY SortOrder FOR XML PATH('')),2,8000)

DECLARE @query NVARCHAR(MAX)
SET @query = '
 SELECT [ClientId], [SurveyDate],'+ @NulltoZeroCols +', [QuestionsAnswered], [TotalScore], CONVERT(DECIMAL(10,2),[QuestionsAnswered])/'+CONVERT(NVARCHAR, @HighScore)+'*[TotalScore] AS [AdjustedScore] FROM 
                (
                SELECT CS.Id AS ClientId, SurveyDate, SurveyId, QuestionText,  AnswerText, COUNT(*) OVER (PARTITION BY ClientId, SurveyDate) AS QuestionsAnswered, SUM(AnswerScore) OVER (PARTITION BY ClientId, SurveyDate) AS TotalScore
                FROM Survey CS
                INNER JOIN SurveyResponse CSR
                ON CS.Id = CSR.SurveyId
                INNER JOIN SurveyQuestion CSQ
                ON CSR.QuestionId = CSQ.Id
                INNER JOIN SurveyAnswer CSA
                ON CSR.AnswerId = CSA.Id
                ) x
                PIVOT
            (  
                MAX(x.AnswerText)
                FOR  [QuestionText] IN (' + @cols + ')
            ) p
            ORDER BY [SurveyDate] DESC;' 

EXEC SP_EXECUTESQL @query

Я играл с ним здесь http://sqlfiddle.com/#! 18 / fcb385 / 19 и это небольшое изменение дает требуемые результаты. По сути, AnswerScore действовал как столбец группировки для пивота.

...