join tables and transpose columns and rows

心不动则不痛 提交于 2019-12-09 20:16:26

问题


I have one table that looks like this called survey_1:

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

note: 1X2X1 represents- survey-id X group-id X question-id

I have another table called survey_questions:

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

The sid (survey-id), gid (group-id) and qid(question-id) define that specific question in this table

I need a query that will give me a result like this:

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

NOTE: My database contains thousands of these columns, so it would be very time consuming to edit every survey to match up perfectly in this format.

Can anyone help out with this? Thank you


回答1:


You need to use 'UNPIVOT', which MySQL unfortunately does not support. You can do a similar thing by hardcoding the column names (but you need to know all the columns in advance) like this:

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

Of course, you can always use some scripting language to generate the column names for you... For example, here is a stored procedure you can make:

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



回答2:


Can you change the table schema? Cause that first table, survey_1 is better written with one row per answer and with the entire key of the other table per row. Like this (add your own indexes)

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

Than the data would be

------------------------------------------
| 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"   |
------------------------------------------

It's going to be much easier to work with and generally a better design.

Here is how it would look http://sqlfiddle.com/#!2/4f1ca/2




回答3:


Create a view for each survey. For the old surveys a simple script should be able to do it, for new surveys make it a part of the process when creating new surveys. This is how the view could look for 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

To build the views a script would roughly do like this.

Find all tables to build views on by running

select table_name 
 from information_schema.tables 
where table_schema = 'test' 
  and table_name like 'survey\_%';

For each view find the union parts by running this for its table

select column_name
  from information_schema.columns 
 where table_name = 'survey_1' 
   and column_name regexp '^[0-9]+X[0-9]+X[0-9]+$';

Extract the number parts and use them when comparing with sid, gid and qid.

This script could also be used to populate new proper tables.



来源:https://stackoverflow.com/questions/12962000/join-tables-and-transpose-columns-and-rows

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!