问题
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