DROP
TABLE
IF
EXISTS
students;
CREATE
TABLE
students(
`id`
INT
(
3
)
NOT
NULL
COMMENT
'主键'
,
`name`
VARCHAR
(
10
)
NOT
NULL
COMMENT
'姓名'
,
`age`
INT
(
3
)
NOT
NULL
COMMENT
'年龄'
,
`class`
VARCHAR
(
10
)
NOT
NULL
COMMENT
'班级'
,
PRIMARY
KEY (`id`)
# 成绩表
DROP
TABLE
IF
EXISTS
grade;
CREATE
TABLE
grade(
`id`
INT
(
3
)
NOT
NULL
COMMENT
'主键'
,
`student_id`
INT
(
3
)
NOT
NULL
COMMENT
'学生id'
,
`subject`
VARCHAR
(
20
)
NOT
NULL
COMMENT
'科目'
,
`grade`
INT
(
3
)
NOT
NULL
COMMENT
'成绩'
,
PRIMARY
KEY (`id`)
# 学生表
INSERT INTO students VALUES(1, '詹溪', 18, '高三(2)班');
INSERT INTO students VALUES(2, '徐柯', 18, '高三(3)班');
INSERT INTO students VALUES(3, '蓝毅', 17, '高三(3)班');
INSERT INTO students VALUES(4, '温邱', 18, '高三(3)班');
# 成绩表
INSERT INTO grade VALUES(1, 1, "math", 98);
INSERT INTO grade VALUES(2, 1, "chinese", 72);
INSERT INTO grade VALUES(3, 1, "english", 100);
INSERT INTO grade VALUES(4, 2, "math", 92);
INSERT INTO grade VALUES(5, 2, "chinese", 95);
INSERT INTO grade VALUES(6, 2, "english", 91);
INSERT INTO grade VALUES(7, 3, "math", 86);
INSERT INTO grade VALUES(8, 3, "chinese", 80);
INSERT INTO grade VALUES(9, 3, "english", 91);
INSERT INTO grade VALUES(10, 4, "math", 95);
INSERT INTO grade VALUES(11, 4, "chinese", 92);
INSERT INTO grade VALUES(12, 4, "english", 93);
普通联合查询
SELECT s.name, s.class, g.subject, g.grade FROM students s
LEFT JOIN grade g ON s.id = g.student_id
现在需要将每个人的成绩整合成一行的多列展示。
固定列就不再赘述了,使用case...when...then
或者if
判断科目即可。
但如果科目不确定,或者是科目太多不想一行行写,就需要使用动态拼接的方式,生成语句。
动态行转列
# 将case...when...then或者if语句动态拼接起来。
SELECT
@sequence :=CONCAT(@sequence,'SUM(IF(subject= "',subject,'",grade,0)) as ',subject, ',') AS sequence
(SELECT DISTINCT subject FROM grade) g,
(SELECT @sequence:="") s;
# 与固定列拼接成查询语句
SET @sql = CONCAT('SELECT s.name, s.class,',@sequence,' SUM(grade) as TOTAL FROM students s LEFT JOIN grade g ON s.id = g.student_id GROUP BY s.id');
# 执行sql
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
到此为止,成功使用sql查出想要的结果。
但是mybatis好像没有执行语句的标签。
只有select
、insert
、update
等。
那么我们还是可以使用拼接语句,再塞到mybatis映射文件中去使用select
标签执行。
实体没有动态字段的属性怎么办?那就使用Map类型接收结果。
使用mybatis实行动态行转列查询
Mapper.xml
<select id="getSequence" resultType="java.lang.String">
SELECT
@sequence :=CONCAT(@sequence,'SUM(IF(subject= "',subject,'",grade,0)) as ',subject, ',') AS sequence
(SELECT DISTINCT subject FROM grade) g,
(SELECT @sequence:="") s;
</select>
<select id="findList" parameterType="java.lang.String" resultType="java.util.Map">
${sql}
</select>
Dao.java
public List<String> getSequence();
public List<Map<String, Object>> findList(String sql);
Service.java
public List<Map<String, Object>> findList() {
List<String> dynamicSequence = dao.getSequence();
String sql = "SELECT s.name, s.class," +
dynamicSequence.get(dynamicSequence.size() - 1) +
" SUM(grade) as TOTAL" +
" FROM students s" +
" LEFT JOIN grade g ON s.id = g.student_id" +
" GROUP BY s.id";
List<Map<String, Object>> mapList = dao.findList(sql);
return mapList;
自此,使用mybatis实现查询行转动态列。
如果前端使用layui,可以参考我的另一篇文章layui-table动态列实现
参考资料:
mysql 行转列 列转行
mybatis 实现自定义sql