连接表并转置列和行

时间:2012-10-18 19:11:29

标签: mysql transpose

我有一个看起来像这个名为survey_1的表:

================================================
|id  | token  |     1X2X1     |    1X2X2       |
=====+========+===============+================|
| 1  |   1    |    YES        | Justin Beiber  |
|----+--------+---------------+----------------|
| 2  |   1    |    YES        | Britney Spears |
|----+--------+---------------+----------------|

注意:1X2X1表示 - survey-id X group-id X question-id

我有另一个名为survey_questions的表:

===============================================================
|sid |   gid  |   qid  |             question                 |
=====+========+===============+===============================|
| 1  |  2     |    1   |  Do you listen to music?             |
|----+--------+-----------------------------------------------|
| 1  |  2     |    2   |  Who is your favorite music artists? |
|----+--------+-----------------------------------------------|

sid(survey-id),gid(group-id)和qid(question-id)定义了此表中的特定问题

我需要一个能给我这样结​​果的查询:

======================================================
|           Question                  |   Answer     |
=========+===========+===============================|
| Do you listen to music?             |    YES       |            
|----------------------------------------------------|
| Who is your favorite music artists? | Justin Beiber| 
|----------------------------------------------------|

注意:我的数据库包含数千个这样的列,因此编辑每个调查以在此格式中完美匹配将非常耗时。

任何人都可以帮忙吗?谢谢

3 个答案:

答案 0 :(得分:4)

您可以更改表架构吗?因为第一个表,survey_1最好用每个答案写一行,每行写一个另一个表的整个键。像这样(添加自己的索引)

create table survey_1 (
  id int,
  token int,
  sid int,
  gid int,
  qid int,
  answer varchar(255)
)

比数据

------------------------------------------
| 1 | 1 | 1 | 2 | 1 | "YES"              |
| 1 | 1 | 1 | 2 | 2 | "Justin Beiber"    |
| 2 | 1 | 1 | 2 | 1 | "YES"              |
| 2 | 1 | 1 | 2 | 2 | "Britney Spears"   |
------------------------------------------

使用起来会更容易,并且通常会有更好的设计。

以下是http://sqlfiddle.com/#!2/4f1ca/2

的外观

答案 1 :(得分:2)

为每个调查创建一个视图。对于旧的调查,一个简单的脚本应该能够做到,因为新的调查使其成为创建新调查时的过程的一部分。这就是视图查找survey_1的方式

create or replace view v_survey_1 as
select id, question, 1X2X1 as answer 
  from question
  join survey_1 s
 where sid = 1
   and gid = 2
   and qid = 1
union
select id, question, 1X2X2 
  from question
  join survey_1 s
 where sid = 1
   and gid = 2
   and qid = 2
;

http://sqlfiddle.com/#!2/63aee/1

要构建视图,脚本大致会这样做。

通过运行

查找要构建视图的所有表
select table_name 
 from information_schema.tables 
where table_schema = 'test' 
  and table_name like 'survey\_%';

对于每个视图,通过为其表

运行此部件来查找联合部件
select column_name
  from information_schema.columns 
 where table_name = 'survey_1' 
   and column_name regexp '^[0-9]+X[0-9]+X[0-9]+$';

提取数字部分并在与sid,gid和qid进行比较时使用它们。

此脚本也可用于填充新的正确表格。

答案 2 :(得分:0)

你需要使用'UNPIVOT',但遗憾的是MySQL不支持。你可以通过硬编码列名来做类似的事情(但你需要提前知道所有列),如下所示:

SELECT survey_questions.Question,
       CASE survey_questions.qid 
         WHEN 1 THEN survey_1.`1X2X1`
         WHEN 2 THEN survey_1.`1X2X2`
         WHEN 3 THEN survey_1.`1X2X3`
         WHEN 4 THEN survey_1.`1X2X4`
       // ...
       END as Answer
FROM survey_questions
JOIN survey_1 
  ON survey_questions.qid = survey_1.id
  AND survey_questions.gid = survey_1.token_id
WHERE survey_questions.sid = 1

当然,您总是可以使用某种脚本语言为您生成列名...例如,以下是您可以创建的存储过程:

CREATE PROCEDURE 'get_qa_for_survey'
(
  IN surveyId INT
)
BEGIN
  DECLARE query1 TEXT; 
  SET @tableName = 'survey_' + surveyId;
  SET query1 = 'SELECT survey_questions.Question,
       CASE survey_questions.qid ';

  DECLARE col_names CURSOR FOR
    SELECT column_name
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE table_name = @tableName
    AND (column_name LIKE surveyId +'X%');
    ORDER BY ordinal_position;

  select FOUND_ROWS() into num_rows;

  SET i = 1;
  the_loop: LOOP    
     IF i > num_rows THEN
        CLOSE col_names;
        LEAVE the_loop;
     END IF;

     FETCH col_names 
     INTO col_name;     
     SET query1 = query1 + ' WHEN ' + i + ' THEN ' + @tableName + '.' + col_name
     SET i = i + 1;  
  END LOOP the_loop;

  SET query1 = query1 + ' END as Answer
    FROM survey_questions
    JOIN ' + @tableName + '
      ON survey_questions.qid = ' + @tableName + '.id
      AND survey_questions.gid = ' + @tableName + '.token_id
    WHERE survey_questions.sid = ' + surveyId; 


  SET @Sql = query1;        
  PREPARE STMT FROM @Sql; 
  EXECUTE STMT; 
  DEALLOCATE PREPARE STMT;
END