Mysql combines the row data according to the conditions, and then transfers the column according to the conditions

Posted by sungpeng on Mon, 24 Jan 2022 16:16:37 +0100

background

As required by the company, it is now necessary to make statistics on the data of the questionnaire filled in by the user. The final presentation style is EXCEL, and the content is the options of each question filled in by the user, that is, the following table style:

User ID numberQuestion 1Question 2Question 3...Question 22
110000190001010011121,4...1
370000199002021002312,5...1,3,4

Let's introduce the related tables first:
1. Questionnaire: topic_ Question (save all the questionnaire questions, which are not used in this case, but only mention too many display fields)
2. Questionnaire options: topic_ Option (option to save all questions)

Field nameField meaning
idAuto increment primary key
question_idQuestion id
optionOption text description
orderOption number for each question
use_flagStart
  1. Questionnaire user filling form: topic_answer (save the filling status of all users. An option for a question filled in by a user is a row of data)
Field nameField meaning
idAuto increment primary key
question_idQuestion id(topic_question.id)
option_idOption ID table primary key (topic_option.id is not the option ID of the corresponding problem)
user_idUser table id
task_idTask id
  1. User table (user_info)
Field nameField meaning
idAuto increment primary key
id_cardID number

sql writing logic:

  1. Because the final output is displayed on the id card number, the corresponding id number should be querying according to the id number id.
  2. Because multiple questions are selected, to display multiple options in the same cell, you need to merge the options that users fill in the same question first;
  3. Because topic_ The answer table stores a row of data as an option for a user's question, so all the question options filled in by the user need to be row to column according to the question number;
  4. Because topic_ Option of answer table_ The ID field is not the option serial number, so you need to perform a joint query to find the corresponding option serial number;

Therefore, the current problems:

  1. How to merge the options of the same question of the same user, that is, the merged row data mentioned in the title;
  2. How to display the same problem of multiple users horizontally: each user is a row of data, except the first column is the ID number, and the remaining column is the option of each question, that is, the row in the title.

sql preparation:

It's easy to say with the above logical process and problems, so after finding the blog related to the merged line, I wrote the first version of sql. This version of sql can merge the data of multiple lines according to the problem id, that is, merge the data of multiple lines according to the conditions in the Title, and turn multiple lines into one line;
Reference blog: Merge multiple rows of data into one row of data in mysql

SELECT 
	USER.id_card,
	answer.question_id,
	GROUP_CONCAT( answer.option_id SEPARATOR ',' ) AS option_id 
FROM
	topic_answer answer
	LEFT JOIN user_info USER ON answer.user_id = USER.id 
GROUP BY
	USER.id_card,
	answer.question_id;

After that, I checked the relevant documents and wrote the second version of sql. This version is basically formed from the target, but there are many pits in the middle, which takes a relatively long time. Later, I will talk about the places that need ideas; However, the row to column conversion is completed, mainly by using GROUP_CONCAT and CASE... WHEN... THEN methods.
Reference blog: mysql row to column, multi row to one row, column to row, one row to multiple columns

SELECT
	answer2.id_card 'ID card No.',
	GROUP_CONCAT( CASE answer2.question_id WHEN 1 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 1',
	GROUP_CONCAT( CASE answer2.question_id WHEN 2 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 2',
	GROUP_CONCAT( CASE answer2.question_id WHEN 3 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 3',
	GROUP_CONCAT( CASE answer2.question_id WHEN 4 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 4',
	GROUP_CONCAT( CASE answer2.question_id WHEN 5 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 5',
	GROUP_CONCAT( CASE answer2.question_id WHEN 6 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 6',
	GROUP_CONCAT( CASE answer2.question_id WHEN 7 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 7',
	GROUP_CONCAT( CASE answer2.question_id WHEN 8 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 8',
	GROUP_CONCAT( CASE answer2.question_id WHEN 9 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 9',
	GROUP_CONCAT( CASE answer2.question_id WHEN 10 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 10',
	GROUP_CONCAT( CASE answer2.question_id WHEN 11 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 11',
	GROUP_CONCAT( CASE answer2.question_id WHEN 12 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 12',
	GROUP_CONCAT( CASE answer2.question_id WHEN 13 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 13',
	GROUP_CONCAT( CASE answer2.question_id WHEN 14 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 14',
	GROUP_CONCAT( CASE answer2.question_id WHEN 15 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 15',
	GROUP_CONCAT( CASE answer2.question_id WHEN 16 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 16',
	GROUP_CONCAT( CASE answer2.question_id WHEN 17 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 17',
	GROUP_CONCAT( CASE answer2.question_id WHEN 18 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 18',
	GROUP_CONCAT( CASE answer2.question_id WHEN 19 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 1',
	GROUP_CONCAT( CASE answer2.question_id WHEN 20 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 20',
	GROUP_CONCAT( CASE answer2.question_id WHEN 21 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 21',
	GROUP_CONCAT( CASE answer2.question_id WHEN 22 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 22' 
FROM
	(
	SELECT 
		DISTINCT(user_info.id_card) AS id_card,
		answer.question_id AS question_id,
		GROUP_CONCAT(answer.option_id SEPARATOR ',' ) AS option_id 
	FROM
		topic_answer answer
		LEFT JOIN user_info user_info ON answer.user_id = user_info.id 
	GROUP BY
		user_info.id_card,
		answer.question_id 
	) as answer2
GROUP BY
	answer2.id_card;

Then, you need to integrate the option id into this, so that the page is displayed with the option id corresponding to each question, not the primary key of the option table, so the third version of sql is shown:

SELECT
	answer2.id_card 'ID card No.',
	GROUP_CONCAT( CASE answer2.question_id WHEN 1 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 1',
	GROUP_CONCAT( CASE answer2.question_id WHEN 2 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 2',
	GROUP_CONCAT( CASE answer2.question_id WHEN 3 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 3',
	GROUP_CONCAT( CASE answer2.question_id WHEN 4 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 4',
	GROUP_CONCAT( CASE answer2.question_id WHEN 5 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 5',
	GROUP_CONCAT( CASE answer2.question_id WHEN 6 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 6',
	GROUP_CONCAT( CASE answer2.question_id WHEN 7 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 7',
	GROUP_CONCAT( CASE answer2.question_id WHEN 8 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 8',
	GROUP_CONCAT( CASE answer2.question_id WHEN 9 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 9',
	GROUP_CONCAT( CASE answer2.question_id WHEN 10 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 10',
	GROUP_CONCAT( CASE answer2.question_id WHEN 11 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 11',
	GROUP_CONCAT( CASE answer2.question_id WHEN 12 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 12',
	GROUP_CONCAT( CASE answer2.question_id WHEN 13 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 13',
	GROUP_CONCAT( CASE answer2.question_id WHEN 14 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 14',
	GROUP_CONCAT( CASE answer2.question_id WHEN 15 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 15',
	GROUP_CONCAT( CASE answer2.question_id WHEN 16 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 16',
	GROUP_CONCAT( CASE answer2.question_id WHEN 17 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 17',
	GROUP_CONCAT( CASE answer2.question_id WHEN 18 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 18',
	GROUP_CONCAT( CASE answer2.question_id WHEN 19 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 1',
	GROUP_CONCAT( CASE answer2.question_id WHEN 20 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 20',
	GROUP_CONCAT( CASE answer2.question_id WHEN 21 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 21',
	GROUP_CONCAT( CASE answer2.question_id WHEN 22 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 22' 
FROM
	(
	SELECT 
		DISTINCT(user_info.id_card) AS id_card,
		answer.question_id AS question_id,
		GROUP_CONCAT(answer.option_id SEPARATOR ',' ) AS option_id 	
	FROM
		topic_answer answer
		LEFT JOIN user_info ON answer.user_id = user_info.id 
		LEFT JOIN topic_option on answer.option_id = topic_option.id
	GROUP BY
		user_info.id_card,
		answer.question_id
	ORDER BY answer.question_id
	) as answer2
GROUP BY
	answer2.id_card;

Finally, improve the results. The first is to sort the option results of each question. The second is that some users fill in it many times, so they need to de duplicate it. The main use is GROUP_CONCAT(distinct XXX order by XXX), because the default is to use commas for segmentation, I will group_ The SEPARATOR in concat has been deleted, and this is the final version;
Reference blog: group_concat sort the functions you don't know and de duplicate them

SELECT
	answer2.id_card 'ID card No.',
	GROUP_CONCAT( CASE answer2.question_id WHEN 1 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 1',
	GROUP_CONCAT( CASE answer2.question_id WHEN 2 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 2',
	GROUP_CONCAT( CASE answer2.question_id WHEN 3 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 3',
	GROUP_CONCAT( CASE answer2.question_id WHEN 4 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 4',
	GROUP_CONCAT( CASE answer2.question_id WHEN 5 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 5',
	GROUP_CONCAT( CASE answer2.question_id WHEN 6 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 6',
	GROUP_CONCAT( CASE answer2.question_id WHEN 7 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 7',
	GROUP_CONCAT( CASE answer2.question_id WHEN 8 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 8',
	GROUP_CONCAT( CASE answer2.question_id WHEN 9 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 9',
	GROUP_CONCAT( CASE answer2.question_id WHEN 10 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 10',
	GROUP_CONCAT( CASE answer2.question_id WHEN 11 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 11',
	GROUP_CONCAT( CASE answer2.question_id WHEN 12 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 12',
	GROUP_CONCAT( CASE answer2.question_id WHEN 13 THEN CAST(answer2.option_id AS char) ELSE NULL END ) 'Question 13',
	GROUP_CONCAT( CASE answer2.question_id WHEN 14 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 14',
	GROUP_CONCAT( CASE answer2.question_id WHEN 15 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 15',
	GROUP_CONCAT( CASE answer2.question_id WHEN 16 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 16',
	GROUP_CONCAT( CASE answer2.question_id WHEN 17 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 17',
	GROUP_CONCAT( CASE answer2.question_id WHEN 18 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 18',
	GROUP_CONCAT( CASE answer2.question_id WHEN 19 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 1',
	GROUP_CONCAT( CASE answer2.question_id WHEN 20 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 20',
	GROUP_CONCAT( CASE answer2.question_id WHEN 21 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 21',
	GROUP_CONCAT( CASE answer2.question_id WHEN 22 THEN CAST(answer2.option_id AS char) ELSE NULL END) 'Question 22' 
FROM
	(
	SELECT 
		DISTINCT(user_info.id_card) AS id_card,
		answer.question_id AS question_id,
		GROUP_CONCAT(distinct topic_option.order order by topic_option.order) AS option_id	
	FROM
		topic_answer answer
		LEFT JOIN user_info ON answer.user_id = user_info.id 
		LEFT JOIN topic_option on answer.option_id = topic_option.id
	GROUP BY
		user_info.id_card,
		answer.question_id
	ORDER BY answer.question_id
	) as answer2
GROUP BY
	answer2.id_card;

Finally, summarize the knowledge learned and the pit you stepped on:

The first and most important thing to learn is how to sort out the logic of solving the problem without a clue. This is mainly to disassemble the problem. You can sort out ideas first, solve it step by step, and consult relevant materials. At the same time, the ability of autonomous learning is also very important, Don't just want to ask others for advice WHEN you encounter problems. Think clearly before you start to do it. THEN there is group_ How to use the concat method in combination with CASE... WHEN... THEN, distinct and order;
The pit I stepped on was actually my own carelessness_ The ID field is originally a number, but after multiple rows of data are merged into one row, it becomes a char type, so the outermost layer is changed from SUM(CASE answer2.question_id WHEN 1 THEN answer2.question_id else 0 end) 1 to GROUP_CONCAT (case answer2.question_id when 1 then cast (answer2.option_id as char) else null end) 1. I thought this would be OK, but I kept reporting sql statement errors. It took a long time to locate it and use group_ After concat, it becomes a string, so it cannot be displayed on the title bar with numbers, so it is changed to GROUP_CONCAT (case answer2. Question_id when 1 then cast (answer2. Option_id as char) else null end) 'question 1', special attention should be paid when using.

Well, I'll write this question first, because I haven't written a slightly more complex sql for a long time, and I haven't used group before_ Concat method, so I want to record this time. Of course, it's a great honor if I can help you at the same time. Similarly, if you have any suggestions or optimization places for the final version of sql, please leave your ideas in the comment area ~

Topics: Java Database MySQL Spring SQL