因公司要求,现需要对用户填写的问卷调查的数据进行统计,最终呈现样式为EXCEL表格,内容为用户填写的每个问题的选项,即如下表格样式:
用户身份证号 | 问题1 | 问题2 | 问题3 | … | 问题22 |
---|---|---|---|---|---|
110000190001010011 | 1 | 2 | 1,4 | … | 1 |
370000199002021002 | 3 | 1 | 2,5 | … | 1,3,4 |
先介绍一下相关的表:
1. 问卷调查问题表:topic_question(保存所有问卷调查的问题,本案例中未用到仅提及不过多展示字段)
2. 问卷调查选项表:topic_option(保存所有问题的选项)
字段名 | 字段含义 |
---|---|
id | 自增主键 |
question_id | 问题id |
option | 选项文字描述 |
order | 针对每个问题的选项序号 |
use_flag | 是否启用 |
字段名 | 字段含义 |
---|---|
id | 自增主键 |
question_id | 问题id(topic_question.id) |
option_id | 选项id表主键(topic_option.id 非对应问题的选项id) |
user_id | 用户表id |
task_id | 任务id |
字段名 | 字段含义 |
---|---|
id | 自增主键 |
id_card | 身份证号 |
所以当前面临的问题:
有了上面的逻辑流程和问题就好说了,于是查找合并行相关的博客之后写出了第一版sql,这一版sql可以将多行的数据根据问题id将选项进行合并,即标题中的根据条件合并行数据,多行转一行;
参考博客: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;
之后,又查阅了相关的文档,写出了第二版sql,该版距离目标基本成型,但是中间却踩了很多坑,耗费时间相对较长,后面再说需要主意的地方;不过还是完成了行转列,主要就是运用了GROUP_CONCAT和CASE…WHEN…THEN方法。
参考博客:mysql 行转列,多行转一行,列转行,一行转多列
SELECT
answer2.id_card '身份证号码',
GROUP_CONCAT( CASE answer2.question_id WHEN 1 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题1',
GROUP_CONCAT( CASE answer2.question_id WHEN 2 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题2',
GROUP_CONCAT( CASE answer2.question_id WHEN 3 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题3',
GROUP_CONCAT( CASE answer2.question_id WHEN 4 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题4',
GROUP_CONCAT( CASE answer2.question_id WHEN 5 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题5',
GROUP_CONCAT( CASE answer2.question_id WHEN 6 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题6',
GROUP_CONCAT( CASE answer2.question_id WHEN 7 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题7',
GROUP_CONCAT( CASE answer2.question_id WHEN 8 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题8',
GROUP_CONCAT( CASE answer2.question_id WHEN 9 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题9',
GROUP_CONCAT( CASE answer2.question_id WHEN 10 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题10',
GROUP_CONCAT( CASE answer2.question_id WHEN 11 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题11',
GROUP_CONCAT( CASE answer2.question_id WHEN 12 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题12',
GROUP_CONCAT( CASE answer2.question_id WHEN 13 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题13',
GROUP_CONCAT( CASE answer2.question_id WHEN 14 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题14',
GROUP_CONCAT( CASE answer2.question_id WHEN 15 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题15',
GROUP_CONCAT( CASE answer2.question_id WHEN 16 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题16',
GROUP_CONCAT( CASE answer2.question_id WHEN 17 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题17',
GROUP_CONCAT( CASE answer2.question_id WHEN 18 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题18',
GROUP_CONCAT( CASE answer2.question_id WHEN 19 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题1',
GROUP_CONCAT( CASE answer2.question_id WHEN 20 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题20',
GROUP_CONCAT( CASE answer2.question_id WHEN 21 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题21',
GROUP_CONCAT( CASE answer2.question_id WHEN 22 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题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;
然后需要将选项id融入到这里面,让页面展示的时候是每个问题对应的选项id,而不是选项表的主键,所以出了第三版sql:
SELECT
answer2.id_card '身份证号码',
GROUP_CONCAT( CASE answer2.question_id WHEN 1 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题1',
GROUP_CONCAT( CASE answer2.question_id WHEN 2 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题2',
GROUP_CONCAT( CASE answer2.question_id WHEN 3 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题3',
GROUP_CONCAT( CASE answer2.question_id WHEN 4 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题4',
GROUP_CONCAT( CASE answer2.question_id WHEN 5 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题5',
GROUP_CONCAT( CASE answer2.question_id WHEN 6 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题6',
GROUP_CONCAT( CASE answer2.question_id WHEN 7 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题7',
GROUP_CONCAT( CASE answer2.question_id WHEN 8 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题8',
GROUP_CONCAT( CASE answer2.question_id WHEN 9 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题9',
GROUP_CONCAT( CASE answer2.question_id WHEN 10 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题10',
GROUP_CONCAT( CASE answer2.question_id WHEN 11 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题11',
GROUP_CONCAT( CASE answer2.question_id WHEN 12 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题12',
GROUP_CONCAT( CASE answer2.question_id WHEN 13 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题13',
GROUP_CONCAT( CASE answer2.question_id WHEN 14 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题14',
GROUP_CONCAT( CASE answer2.question_id WHEN 15 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题15',
GROUP_CONCAT( CASE answer2.question_id WHEN 16 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题16',
GROUP_CONCAT( CASE answer2.question_id WHEN 17 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题17',
GROUP_CONCAT( CASE answer2.question_id WHEN 18 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题18',
GROUP_CONCAT( CASE answer2.question_id WHEN 19 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题1',
GROUP_CONCAT( CASE answer2.question_id WHEN 20 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题20',
GROUP_CONCAT( CASE answer2.question_id WHEN 21 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题21',
GROUP_CONCAT( CASE answer2.question_id WHEN 22 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题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;
最后,再将结果进行完善,第一个是每一个问题的选项结果进行排序,第二个是因为有的用户填写了多次所以需要去重,主要使用的是GROUP_CONCAT(distinct XXX order by XXX),因为默认的就是使用逗号进行分割,所以我将GROUP_CONCAT里面的SEPARATOR删除了,此次为最终版(因为现在表中只有这一次问卷调查,所以条件中没有对task_id进行筛选);
参考博客:group_concat你所不知道的功能排序,去重
SELECT
answer2.id_card '身份证号码',
GROUP_CONCAT( CASE answer2.question_id WHEN 1 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题1',
GROUP_CONCAT( CASE answer2.question_id WHEN 2 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题2',
GROUP_CONCAT( CASE answer2.question_id WHEN 3 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题3',
GROUP_CONCAT( CASE answer2.question_id WHEN 4 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题4',
GROUP_CONCAT( CASE answer2.question_id WHEN 5 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题5',
GROUP_CONCAT( CASE answer2.question_id WHEN 6 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题6',
GROUP_CONCAT( CASE answer2.question_id WHEN 7 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题7',
GROUP_CONCAT( CASE answer2.question_id WHEN 8 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题8',
GROUP_CONCAT( CASE answer2.question_id WHEN 9 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题9',
GROUP_CONCAT( CASE answer2.question_id WHEN 10 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题10',
GROUP_CONCAT( CASE answer2.question_id WHEN 11 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题11',
GROUP_CONCAT( CASE answer2.question_id WHEN 12 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题12',
GROUP_CONCAT( CASE answer2.question_id WHEN 13 THEN CAST(answer2.option_id AS char) ELSE NULL END ) '问题13',
GROUP_CONCAT( CASE answer2.question_id WHEN 14 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题14',
GROUP_CONCAT( CASE answer2.question_id WHEN 15 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题15',
GROUP_CONCAT( CASE answer2.question_id WHEN 16 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题16',
GROUP_CONCAT( CASE answer2.question_id WHEN 17 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题17',
GROUP_CONCAT( CASE answer2.question_id WHEN 18 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题18',
GROUP_CONCAT( CASE answer2.question_id WHEN 19 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题1',
GROUP_CONCAT( CASE answer2.question_id WHEN 20 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题20',
GROUP_CONCAT( CASE answer2.question_id WHEN 21 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题21',
GROUP_CONCAT( CASE answer2.question_id WHEN 22 THEN CAST(answer2.option_id AS char) ELSE NULL END) '问题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;
第一个学到的也是最主要的,就是拿到这个问题时,在没有头绪的情况下,如何才能梳理出解决问题的逻辑,这个主要是对问题进行拆解,大家可以先整理出思路再一步一步去解决,去查阅相关的资料,同时自主学习的能力也是很重要的,不要遇到问题就只想跟别人请教,先自己动脑想清楚再下手去做。然后就是GROUP_CONCAT方法的用法,再结合CASE…WHEN…THEN,distinct,order如何使用;
踩到的坑其实就是我自己的粗心,option_id字段本来是数字,但是多行数据合并成一行之后就变成了char类型,所以最外层由SUM(CASE answer2.question_id WHEN 1 THEN answer2.question_id else 0 end) 1 改成了 GROUP_CONCAT( CASE answer2.question_id WHEN 1 THEN CAST(answer2.option_id AS char) ELSE NULL END) 1 , 本以为这样就可以了,但是一直再报sql语句的错误,定位了好久才定位出来 使用了GROUP_CONCAT之后就变成了字符串,所以不能用数字展示到标题栏上,遂改为 GROUP_CONCAT( CASE answer2.question_id WHEN 1 THEN CAST(answer2.option_id AS char) ELSE NULL END) ‘问题1’,使用的时候还是需要特别注意的。
好了,这个问题就先写到这里,因为好久没写稍微复杂点的sql了,而且之前没用过GROUP_CONCAT方法,所以想着把这次记录一下,如果可以同时帮到你当然是十分荣幸的,同样如果对最终版的sql有什么建议或者可以优化的地方欢迎评论区留下你的想法~