Разделить несколько столбцов на несколько строк
У меня есть таблица с этой структурой.
UserID | UserName | AnswerToQuestion1 | AnswerToQuestion2 | AnswerToQuestion3
1 | John | 1 | 0 | 1
2 | Mary | 1 | 1 | 0
Я не могу понять, какой SQL-запрос я бы использовал для получения набора результатов следующим образом:
UserID | UserName | QuestionName | Response
1 | John | AnswerToQuestion1 | 1
1 | John | AnswerToQuestion2 | 0
1 | John | AnswerToQuestion3 | 1
2 | Mary | AnswerToQuestion1 | 1
2 | Mary | AnswerToQuestion2 | 1
2 | Mary | AnswerToQuestion3 | 0
Я пытаюсь разбить три столбца на три отдельные строки. Возможно ли это?
Ответы
Ответ 1
SELECT
Y.UserID,
Y.UserName,
QuestionName = 'AnswerToQuestion' + X.Which,
Response =
CASE X.Which
WHEN '1' THEN AnswerToQuestion1
WHEN '2' THEN AnswerToQuestion2
WHEN '3' THEN AnswerToQuestion3
END
FROM
YourTable Y
CROSS JOIN (SELECT '1' UNION ALL SELECT '2' UNION ALL SELECT '3') X (Which)
Это одинаково хорошо работает с UNPIVOT (иногда лучше) и работает также в SQL 2000.
Я воспользовался сходством вопросов, чтобы создать столбец QuestionName, но, конечно, это будет работать с различными именами вопросов.
Обратите внимание, что если ваш список вопросов длинный или имена вопросов длинны, вы можете поэкспериментировать с 2 столбцами в таблице X, один для номера вопроса и один для имени вопроса. Или, если у вас уже есть таблица со списком вопросов, тогда CROSS JOIN. Если некоторые вопросы являются NULL, то проще всего поставить вышеуказанный запрос в CTE или производную таблицу, а затем добавить WHERE Response IS NOT NULL
.
Ответ 2
В соответствии с Itzik Ben-Gan в В Microsoft SQL Server 2008: запрос T-SQL, SQL Server проходит три шага при открытии таблицы
- Создание копий
- Извлечь элементы
- Удалить строки с помощью NULL
Шаг 1: Создание копий
Создается виртуальная таблица с копией каждой строки в таблице orignal для каждого столбца, который не разрешен.
Кроме того, символьная строка имени столбца сохраняется в новом столбце (назовите это столбец QuestionName). * Примечание. Я изменил значение в одном из столбцов на NULL, чтобы показать полный процесс.
UserID UserName AnswerTo1 AnswerToQ2 AnswerToQ3 QuestionName
1 John 1 0 1 AnswerToQuestion1
1 John 1 0 1 AnswerToQuestion2
1 John 1 0 1 AnswerToQuestion3
2 Mary 1 NULL 1 AnswerToQuestion1
2 Mary 1 NULL 1 AnswerToQuestion2
2 Mary 1 NULL 1 AnswerToQuestion3
Шаг 2: Извлеките элементы
Затем создается другая таблица, которая создает новую строку для каждого значения из столбца источника, который соответствует
к значению символьной строки в столбце QuestionName. Значение сохраняется в новом столбце (назовите это столбец "Ответ" ).
UserID UserName QuestionName Response
1 John AnswerToQuestion1 1
1 John AnswerToQuestion2 0
1 John AnswerToQuestion3 1
2 Mary AnswerToQuestion1 1
2 Mary AnswerToQuestion2 NULL
2 Mary AnswerToQuestion3 1
Шаг 3: Удалите строки с помощью NULLS
Этот шаг отфильтровывает любые строки, созданные с нулевыми значениями в столбце "Ответ" . Другими словами,
если какой-либо из столбцов AnswerToQuestion имеет нулевое значение, он не будет представлен как непривязанная строка.
UserID UserName QuestionName Response
1 John AnswerToQuestion1 1
1 John AnswerToQuestion2 0
1 John AnswerToQuestion3 1
2 Mary AnswerToQuestion1 1
2 Mary AnswerToQuestion3 1
Если вы выполните эти шаги, вы можете
- CROSS ПРИСОЕДИНИТЬ все строки в таблице против каждого AnswerToQuestion
имя столбца, чтобы получить копии строк.
- Заполнение столбца "Ответ"
на соответствие столбцу источника и QuestionName
- Удалите NULL, чтобы получить тот же
результаты без использования UNPIVOT.
Пример ниже:
DECLARE @t1 TABLE (UserID INT, UserName VARCHAR(10), AnswerToQuestion1 INT,
AnswertoQuestion2 INT, AnswerToQuestion3 INT
)
INSERT @t1 SELECT 1, 'John', 1, 0, 1 UNION ALL SELECT 2, 'Mary', 1, NULL, 1
SELECT
UserID,
UserName,
QuestionName,
Response
FROM (
SELECT
UserID,
UserName,
QuestionName,
CASE QuestionName
WHEN 'AnswerToQuestion1' THEN AnswerToQuestion1
WHEN 'AnswerToQuestion2' THEN AnswertoQuestion2
ELSE AnswerToQuestion3
END AS Response
FROM @t1 t1
CROSS JOIN (
SELECT 'AnswerToQuestion1' AS QuestionName
UNION ALL SELECT 'AnswerToQuestion2'
UNION ALL SELECT 'AnswerToQuestion3'
) t2
) t3
WHERE Response IS NOT NULL
Ответ 3
Предполагая, что SQL Server 2005+ вы можете использовать UNPIVOT
;with YourTable as
(
SELECT 1 UserID,'John' UserName,1 AnswerToQuestion1,0 AnswerToQuestion2,1 AnswerToQuestion3
UNION ALL
SELECT 2, 'Mary', 1, 1, 0
)
SELECT UserID, UserName, QuestionName, Response
FROM YourTable
UNPIVOT
(Response FOR QuestionName IN
(AnswerToQuestion1, AnswerToQuestion2,AnswerToQuestion3)
)AS unpvt;