我有以下 MySQL 模式 -
注意:我知道这不是一个理想的模式,但我使用的是遗留代码,所以我无法完全控制完全更改模式
CREATE TABLE `student` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL COLLATE 'utf8mb4_unicode_ci',
PRIMARY KEY (`id`)
);
CREATE TABLE `subject` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`student_id` INT(10) NOT NULL DEFAULT '0',
`title` VARCHAR(255) NOT NULL DEFAULT '0' COLLATE 'utf8mb4_unicode_ci',
`marks` INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
);
示例数据 -
INSERT INTO `student` (`id`, `name`) VALUES
(1, 'Foo'),
(2, 'Bar'),
(3, 'Baz');
INSERT INTO `subject` (`id`, `student_id`, `title`, `marks`) VALUES
(1, 1, 'math', 25),
(2, 1, 'physics', 35),
(3, 1, 'chemistry', 45),
(4, 2, 'math', 85),
(5, 2, 'physics', 65),
(6, 2, 'chemistry', 65);
我正在尝试使用 JPA Criteria API 编写的查询 -
SELECT st.name
, max(if(sub.title = 'math', sub.marks, 0)) as math
, max(if(sub.title = 'physics', sub.marks, 0)) as physics
, max(if(sub.title = 'chemistry', sub.marks, 0)) as chemistry
FROM student st
LEFT OUTER JOIN subject sub ON st.id = sub.student_id
GROUP BY st.name;
样本结果-
| name | math | physics | chemistry |
| ---- | -----| --------| --------- |
| Bar | 85 | 65 | 65 |
| Baz | 0 | 0 | 0 |
| Foo | 25 | 35 | 45 |
到目前为止我尝试了什么-
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<StudentMark> dataQuery = criteriaBuilder.createQuery(StudentMark.class);
Root<Student> root = dataQuery.from(Student.class);
Join<Student, Subject> studentSubjectJoin = root.join(ReflectUtil.getFieldName(Student.class, Student::getSubjectMarks), JoinType.LEFT);
dataQuery.multiselect(root.get(ReflectUtil.getFieldName(Student.class, Student::getName)),
criteriaBuilder.max(studentSubjectJoin.get(ReflectUtil.getFieldName(Subject.class, Subject::getValue))),
criteriaBuilder.max(studentSubjectJoin.get(ReflectUtil.getFieldName(Subject.class, Subject::getValue))),
criteriaBuilder.max(studentSubjectJoin.get(ReflectUtil.getFieldName(Subject.class, Subject::getValue))));
dataQuery.groupBy(root.get(ReflectUtil.getFieldName(Student.class, Student::getStudentId)));
this.entityManager.createQuery(dataQuery);
我不知道如何根据 SQL 查询在 MAX 聚合函数中编写 IF。
最佳答案
查询等同于:
SELECT st.name
, MAX(CASE WHEN sub.title = 'math' THEN sub.marks ELSE 0 END) as math
, MAX(CASE WHEN sub.title = 'physics' THEN sub.marks ELSE 0 END) as physics
, MAX(CASE WHEN sub.title = 'chemistry' THEN sub.marks ELSE 0 END) as chemistry
FROM student st
LEFT OUTER JOIN subject sub ON st.id = sub.student_id
GROUP BY st.name;
在条件 API 中:
dataQuery.multiselect(root.get(Student_.name),
criteriaBuilder.max(
criteriaBuilder.selectCase()
.when(criteriaBuilder.equal(studentSubjectJoin.get(Subject_.title), criteriaBuilder.literal("math")), studentSubjectJoin.get(Subject_.marks))
.otherwise(criteriaBuilder.literal(0))
).alias("math"),
criteriaBuilder.max(...)
...
);
(为了清晰起见,我使用了静态元模型表示法而不是反射调用;作为旁注,您可能想考虑这样做,它大大提高了可读性)
关于java - JPA 标准 API : Aggregating on Multiple Columns with IF Condition,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57800309/