Разделить несколько столбцов на несколько строк - PullRequest
12 голосов
/ 09 сентября 2010

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

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

Я пытаюсь разделить три столбца на три отдельные строки. Это возможно?

Ответы [ 3 ]

7 голосов
/ 10 сентября 2010
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, но, конечно, это будет работать с разными именами вопросов.

Обратите внимание, что если ваш список вопросов длинный или имена вопросов длинные, вы можете поэкспериментировать с двумя столбцами в таблице X, один для номера вопроса и один для имени вопроса. Или, если у вас уже есть таблица со списком вопросов, тогда присоединяйтесь к ней. Если некоторые вопросы имеют значение NULL, проще всего поместить указанный выше запрос в CTE или производную таблицу, а затем добавить WHERE Response IS NOT NULL.

6 голосов
/ 10 сентября 2010

Согласно Ицик Бен-Гану в Внутри Microsoft SQL Server 2008: запросы T-SQL , SQL Server выполняет три шага при удалении таблицы:

  1. Создание копий
  2. Извлечение элементов
  3. Удалить строки с NULL

Шаг 1. Создание копий

Виртуальная таблица создается с копией каждой строки в исходной таблице для каждого столбца, который не был развернут. Кроме того, символьная строка имени столбца сохраняется в новом столбце (назовите этот столбец 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. Значение сохраняется в новом столбце (назовите его столбцом Response).

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

Этот шаг отфильтровывает все строки, которые были созданы с нулевыми значениями в столбце Response. Другими словами, если какой-либо из столбцов 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

Если вы выполните эти шаги, вы можете

  1. CROSS СОЕДИНИТЬ все строки таблицы с каждым ответом на вопрос Имя столбца для получения копий строк
  2. Заполните столбец Ответ на основе в сопоставлении исходного столбца и QuestionName
  3. Удалите 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
5 голосов
/ 09 сентября 2010

При условии, что 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;
...