2015-10-20 2 views
1

Редактирование: я использую Microsoft SQL Server Management Studio для запуска моих запросов. Microsoft SQL Server Standard Edition (64-разрядная версия) Я думаю.Строки запросов SQL к столбцам

У меня есть сложный запрос для запуска. Я понятия не имел, как это сделать, поэтому я пошел и напишу запрос, который составляет около 500 строк и много соединений. Не так, как должно быть купол.

Моя структура данных:

id  user_id  question_id  answer1  
1   1    1    a   
2   1    2    c   
3   1    3    a   
4   2    1    c   
5   2    2    a   
...  ...   ...    ...   

Есть более 700 пользователей. Каждый пользователь ответил около 60 вопросов (раз 2, ответы на каждый вопрос 2, но это не имеет значения, если я могу получить хороший запрос для первого ответа). Есть некоторые вопросы, на которые я не заинтересован (и должен фактически пропустить).

Мой текущий результат состоит в следующем (хороший результат, но запрос слишком вертикальной качки):

user_id q1 q2 q3 q4 q8 q9 ... q60 
1   a  b  c  d  b  a  ... a 
2   b  a  c  a  c  b  ... w 
3   y  a  w  ... ... 

Таким образом, в основном я хотел бы создать массив, скажем [1,2,3,4,8,9], говоря я заинтересован в эти идентификаторы запроса и запрос, поэтому я получаю эти столбцы как приведенный выше пример. Я не знаю, как это сделать.

Мой текущий запрос в подобных:

SELECT C.user_id, Q1, Q2, Q3, Q4, Q8, ... 
FROM (
    SELECT A.user_id, Q1, // and here tons of unions 
+0

В этом случае вам необходимо написать Dynamic Sql i.e. С помощью запроса генерации массива, а затем выполнить его. В sql-сервере вы можете запускать динамический запрос с помощью EXEC («Выбрать ...») – SeeTheC

+0

Ваши данные и данные не совпадают, это намеренно? Кроме того, пометьте ваши данные СУБД. – DarkKnight

+1

Какая СУБД вы используете? Postgres? Oracle? –

ответ

1

EDIT: упрощена с использованием только answer1:

DECLARE @tbl TABLE(id INT,user_id INT,question_id INT,answer1 VARCHAR(1),answer2 VARCHAR(1)); 
INSERT INTO @tbl VALUES  
(1,1,1,'a','x')   
,(2,1,2,'c','y')   
,(3,1,3,'a','y')   
,(4,2,1,'c','y')   
,(5,2,2,'a','x'); 

WITH AllAnswers AS 
(
    SELECT p.* 
    FROM 
    (
     SELECT tbl.user_id 
       ,'q' + CAST(tbl.question_id AS VARCHAR(10)) AS columnName 
       ,answer1 
     FROM @tbl AS tbl 
    ) AS x 
    PIVOT 
    (
     MIN(answer1) FOR columnName IN(q1,q2,q3 /*Add your question numbers here*/) 
    ) AS p 
) 
SELECT aa.user_id 
     ,aa.q1 
     ,aa.q2 
     ,aa.q3 
     /*Get only the questions you want*/ 
FROM AllAnswers AS aa 

/* Result 

user_id q1 q2 q3 
1  a c a 
2  c a NULL 

*/ 

Может быть, это решение для Вас:

Просто краткое объяснение : Когда вы пишете о двух ответах на каждый вопрос, я помещаю этот второй ответ в тестовый набор. Чтобы разрешить PIVOT с более чем одним столбцом, я использую трюк, чтобы согласовать оба ответа как псевдо-XML. Это снова поворачивается и разворачивается внутренним индексом.

Результат - это список всех пользователей со всеми ответами на все вопросы. С помощью последнего SELECT вы можете выбрать, какие вопросы/ответы вы хотите получить.

DECLARE @tbl TABLE(id INT,user_id INT,question_id INT,answer1 VARCHAR(1),answer2 VARCHAR(1)); 
INSERT INTO @tbl VALUES  
(1,1,1,'a','x')   
,(2,1,2,'c','y')   
,(3,1,3,'a','y')   
,(4,2,1,'c','y')   
,(5,2,2,'a','x'); 

WITH AllAnswers AS 
(
    SELECT p.user_id 
      ,CAST(p.q1 AS XML).value('x[1]','varchar(1)') AS q1_1 
      ,CAST(p.q1 AS XML).value('x[2]','varchar(1)') AS q1_2 
      ,CAST(p.q2 AS XML).value('x[1]','varchar(1)') AS q2_1 
      ,CAST(p.q2 AS XML).value('x[2]','varchar(1)') AS q2_2 
      ,CAST(p.q3 AS XML).value('x[1]','varchar(1)') AS q3_1 
      ,CAST(p.q3 AS XML).value('x[2]','varchar(1)') AS q3_2 
      /*Add all your question numbers here*/ 
    FROM 
    (
     SELECT tbl.user_id 
       ,'q' + CAST(tbl.question_id AS VARCHAR(10)) AS columnName 
       ,'<x>' + ISNULL(answer1,'') + '</x><x>' + ISNULL(answer2,'') + '</x>' AS BothAnswers 
     FROM @tbl AS tbl 
    ) AS x 
    PIVOT 
    (
     MIN(BothAnswers) FOR columnName IN(q1,q2,q3 /*Add your question numbers here*/) 
    ) AS p 
) 
SELECT aa.user_id 
     ,aa.q1_1 
     ,aa.q1_2 
     ,aa.q2_1 
     ,aa.q2_2 
     ,aa.q3_1 
     ,aa.q3_2 
     /*Get only the questions you want*/ 
FROM AllAnswers AS aa 
+0

Я поработаю над этим, спасибо за продуманный пример! С «двумя ответами» я имею в виду, что таблица имеет два столбца ответа (см. «Answer1», есть также «ответ2»). Мне не нужно смотреть на второй ответ: мне нужны две таблицы результатов, одна для ответа 1 и одна для ответа2. Поэтому я мог бы использовать запрос и установить его для ответа из столбца answer1, а затем тот же запрос, но из столбца anwer2. – Tjab

+0

@Tjab, я упростил свой пример, чтобы использовать только answer1. Я не думаю, что это можно сделать намного проще ... В финальном SELECT у вас есть свободный выбор, чтобы выбрать только нулевые столбцы. – Shnugo

0
SELECT * 
FROM 
(
    SELECT [user_id], 
     [answer1], 
     row_number() OVER(PARTITION BY [user_id] ORDER BY [question_id]) rn 
    FROM [table] 
) d 
PIVOT 
(
    MAX([answer1]) 
    FOR rn in ([1], [2], [3], [4], [5], [6]) 
) piv 

работает очень хорошо, за одну ошибку. user_id = 1 не имеет ответов для question_id = 3, но у него есть для question_id = 4. Мой результат помещает ответ на 4, чтобы 3:

user_id 1 2 3 4 5 6 
1   a b c   NULL NULL 
2   a b c d NULL NULL 

С помощью этих данных:

user_id question_id answer1 
1   1    a 
1   2    b 
1   4    c 
1   5          (anwer1 = empty string) 
1   6    NULL 
2   1    a 
2   2    b 
2   4    c 
2   5    d 
2   6    NULL 

Должно быть дано:

user_id 1 2 3 4 5 6 
1   a b NULL c   NULL 
2   a b NULL c d NULL 

Так ошибка: если запись не найдена, используется ответ на «следующий вопрос».

+0

ROW_NUMBER вернется с работающим номером. Если в таблице нет ответа, ваш «rn» пропустит одно значение. Вы можете попробовать использовать таблицу Tally, но мой подход в моем ответе, безусловно, более надежный ... что с ним не так? – Shnugo

+0

Привет, не могли бы вы решить свою проблему? Помог ли мой (отредактированный) ответ? Если да, было бы очень хорошо проголосовать за это, и, если он решит вашу проблему, отметьте ее как принятую, thx! – Shnugo

+0

Да, спасибо! Извините, я вернулся очень и очень поздно. Отмечено, как принято, еще раз спасибо! – Tjab

Смежные вопросы