SELECT 3 > 1 or 3 > 4 and 3 > 4 //结果为true
等价于 SELECT 3 > 1 or ( 3 > 4 and 3 > 4)
SELECT * from A A WHERE
(a = 'xx' and b = 'xx' and c in (xx1,xx2))
and
(d = '真(写死)' or ( d= '假(写死)' and 0 < select count(*) from B where e = 'xx' and f = A.a))
Specification<T> specification = (root, cQ, cB)->{
// 条件集合
List<Predicate> predicates = new LinkedList<>();
//动态生成条件a
if (StringUtils.isNotBlank(a)){
predicates.add(cB.equal(root.get("a"), xx));
}
// 动态生成条件b
if (StringUtils.isNotBlank(b)){
predicates.add(cB.equal(root.get("b"), xx));
}
// 动态生成范围查询条件c c是一个数组 比如: string[] c
if ( c != null && c.length>0){
cB.In<String> in = cB.in(root.get("c"));
for (String e : c) {
in.value(e);
}
predicates.add(in);
}
// 生成第一个条件d
Predicate p3 = cB.equal(root.get("d"), "真(写死)");
// 生成第二个条件d
Predicate p1 = cB.equal(root.get("d"), "假(写死)");
// 创建子查询 ========= 即select count(*) from B where e = 'xx' and f = A.a)部分==============
Subquery<Long> subquery = cQ.subquery(Long.class); //子查询select的输出类型 (这里是求count)
Root<ExamStaffList> subRoot = subquery.from(B.class); // 相当于 from B 表
// 生成子查询条件1
Predicate subP1 = cB.equal(subRoot.get("e"), xx);
// 生成子查询条件2
Predicate subP2 = cB.equal(subRoot.get("f"), root.get("a"));
// 将 subP1 和 subP1 用 and拼接生成新的条件, 并作为subquery的where条件
subquery.where(cB.and(subPredicate1,subPredicate2));
// 选择select出什么
subquery.select(cB.count(subRoot.get("e"))); // 相当于 select count(e)
// 构建复合条件 0 < select count(*) from B where e = 'xx' and f = A.a)
Predicate p4 = cB.greaterThan(subquery,(long)0);
==================================================================================================
// 用 and 将条件集合所有条件用and拼接生成新的条件
Predicate tp1 = cB.and(predicates.toArray(new Predicate[0]));
// 相当于拼接 (d = '真(写死)' or ( d= '假(写死)' and 0 < select count(*) from B where e = 'xx' and f = A.a))
Predicate tp2 =cB.or(p1,cB.and(p3,p4))
// 最后用and拼接 tp1 和 tp2 后把最终条件返回, 等价于原sql最外层的那个 and 操作
return cB.and(tp1,tp2);
};
return specification;
SELECT m.name,m.type , count(m.name), (SELECT count(*) from E WHERE name = e.name and username = xx) as rightCOunt
from E e INNER JOIN M m on e.username = m.name
WHERE m.type in ('网优') and m.name like "%2%"
GROUP BY m.name
limit 0,10
假设E和M关系为
class E {
private Long id;
private String username;
@ManyToOne
@JoinColumn(name = "name")
private M m;
}
class M{
private String name;
private String type;
}
对应jpa为:
class ResultDto {
private String name;
private String type;
private Integer nameCount;
private Integer roghtCount;
// 注意: 一定要创建构造函数而且构造函数的参数数量要跟select的个数一样,不然结果集无法注入
省略构造函数......
}
// 注入 EntityManager
@PersistenceContext
private EntityManager entityManager;
//
int page = 0;
int size = 10;
CriteriaBuilder cB = entityManager.getCriteriaBuilder();
// 泛型是设置要查询的结果集
CriteriaQuery<ResultDto> query = cB.createQuery(ResultDto.class);
// 从哪张表查
Root<E> root = query.from(E.class);
// 动态拼接where条件
List<Predicate> predicateList = new ArrayList<>();
if (StringUtils.isNotBlank(examName)){
predicateList.add(cB.like(root.get("examMission").get("name").as(String.class),"%"+examName+"%"));
}
if (type != null && type.length > 0){
CriteriaBuilder.In<Object> in = cB.in(root.get("examMission").get("type"));
for (String e : type) {
in.value(e);
}
predicateList.add(in);
}
if (predicateList.size() > 0)
query.where(predicateList.toArray(new Predicate[0]));
// 创建子查询,对应原生sql中select的(SELECT count(*) from E WHERE name = e.name and username = xx) as rightCOunt
Subquery<Long> subquery = query.subquery(Long.class); // 子查询的结果集类型 ,这里是count(*)所以用long或者int都行
Root<E> subRoot = subquery.from(E.class); // 子查询从哪张表查,这里是 from E
// 先把原生sql要select的字段列出来
Expression<String> nameField = root.get("m").get("name");
Expression<String> typeField = root.get("m").get("type").as(String.class);
Expression<Integer> nameCountFidld = cB.count(root).as(Integer.class);
Predicate subP1 = cB.equal(subRoot.get("m").get("name"), nameField); // 构建查询条件: name = e.name
Predicate subP2 = cB.equal(subRoot.get("username").as(String.class), xx); // 构建查询条件: username = xx
// 拼接subquery的select和where条件
subquery.select(cB.count(subRoot).as(Long.class)).where(cB.and(subP1,subP2));
// 拼接各部分
query.multiselect(nameField,typeField,nameCountFidld,subquery.getSelection())
.groupBy(root.get("examMission").get("name"));;
List<ResultDto> counts = entityManager.createQuery(query).getResultList();
int totalCount = counts.size(); // 分页返回的总记录数
// 执行查询
TypedQuery<ExamResultStaDto> typedQuery = entityManager.createQuery(query);
typedQuery.setFirstResult(page * size); // 设置分页limit a,b 的a
typedQuery.setMaxResults(size); // 设置分页limit a,b 的b
// 获得结果集
List<ExamResultStaDto> resultList = typedQuery.getResultList();
// 构造分页对象并返回
PageRequest pageRequest = PageRequest.of(page, size);
return new PageImpl<>(resultList,pageRequest,totalCount);
这里就不给对比原生sql和jpa实现的对比了, 就是自定义根据条件动态条件拼接sql字符串
// 假设这里是动态拼接后的字符串
String sql = "select ......case when..... where ...... group by...order by limie ....";
// 一般需要分页就要计算总记录数,这个sql跟上面不同是只select count即查出总记录数
String countSql = "select count(*) .....";
// 使用entityManager 创建原生sql查询
Query nativeQuery = entityManager.createNativeQuery(sql);
Query countQuery = entityManager.createNativeQuery(countSql);
// 获得结果, 返回的结果集会用二维集合保存,即数据库select出来的每一行记录用Object[]保存
List<Object[]> resultList = nativeQuery.getResultList();
Object totalSize = countQuery.getSingleResult(); // 总记录数
// 一般需要将 resultList 转换为对象存储 省略.......
假设resultList 被转换为 List<XXXX> xxlist 对象集合
// 返回自定义Page对象
return new PageImpl<XXXX>(xxlist,PageRequest.of(page,size),Long.value(totalSize+""));