Разделить несколько столбцов на несколько строк

У меня есть таблица с этой структурой.

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;