JPA编程中自定义SQL语句使用case/when语句实现分页查询和分类排序的示例

news2024/11/17 19:43:01

一、需求背景

查询我发起的以及被邀请的工单列表,要求分页查询,排序的具体要求是:

  • 先按状态排序,未处理的排前面
  • 再按处理人排序,被邀请的排前面,自己发起的排后面
  • 最后按修改时间倒序

处理状态包括三种:

  • 0-未处理;
  • 1-已同意;
  • 2-已拒绝

邀请表的ddl:

CREATE TABLE `join_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `course_no` varchar(32) NOT NULL COMMENT '课程编号',
  `created_date` datetime DEFAULT current_timestamp() COMMENT '创建时间',
  `creator_id` bigint(20) NOT NULL COMMENT '创建者ID',
  `deleted` tinyint(1) NOT NULL DEFAULT 0 COMMENT '逻辑删除状态:0-正常;1-已删除',
  `modified_date` datetime DEFAULT current_timestamp() COMMENT '更新时间',
  `receive_id` bigint(20) NOT NULL COMMENT '接受邀请人ID',
  `status` smallint(1) NOT NULL COMMENT '状态,0-未处理;1-已同意;2-已拒绝',
  PRIMARY KEY (`id`),
  KEY `IDX_courseNo` (`course_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  • Entity
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import javax.persistence.*;
import java.util.Date;


/**
 * 邀请记录表
 *
 * @author xxx
 */
@Getter
@NoArgsConstructor
@Table(name = "join_log", indexes = {
        @Index(name = "IDX_courseNo", columnList = "course_no")
})
@Entity
@EntityListeners(AuditingEntityListener.class)
public class JoinLog {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "course_no", nullable = false, columnDefinition = "varchar(32) COMMENT '课程编号'")
    private String courseNo;

    @Column(name = "creator_id", nullable = false, columnDefinition = "bigint COMMENT '创建者ID'")
    private long creatorId;

    @Column(name = "receive_id", nullable = false, columnDefinition = "bigint COMMENT '接受邀请人ID'")
    private long receiveId;

    @Column(name = "status", nullable = false, columnDefinition = "smallint(1) COMMENT '状态,0-未处理;1-已同意;2-已拒绝'")
    private JoinLogStatus status;

    @CreatedDate
    @Column(name = "created_date", columnDefinition = "datetime DEFAULT NOW() COMMENT '创建时间'")
    private Date createdDate;

    @LastModifiedDate
    @CreatedDate
    @Column(name = "modified_date", columnDefinition = "datetime DEFAULT NOW() COMMENT '更新时间'")
    private Date modifiedDate;

    @Column(name = "deleted", nullable = false, columnDefinition = "tinyint(1) default 0 COMMENT '逻辑删除状态:0-正常;1-已删除'")
    private LogicDeleteEnum deleted;
}

二、目标

手写sql语句,实现数据的排序效果见下:

select jl.*
from join_log jl  where (jl.creator_id = 1192660 or jl.receive_id  = 1192660) and jl.deleted = 0 
order by case when jl.status=0 then 0 else 1 end asc,
 case when jl.creator_id=1192660 then 0 else 1 end desc,  
 jl.modified_date desc 
 limit 0,10;

在这里插入图片描述

三、分页查询

jpa已很好地支持分页查询,见类JpaSpecificationExecutor.java,不需要你去计算limit 0,10还是limit 10,20,返回的实体也已是分页类Page。当然,你也不需要去额外编写count()求总记录数的sql语句。

在这里插入图片描述
所以,我们的自定义分页查询的出入参仿照着写。

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

Page<T> query(@Param("pageable") Pageable pageable);

下面是jpa对分页的具体实现:

import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class JoinLogService {

    private final JoinLogRepository joinLogRepository;

    public Page<JoinLog> queryJoinLog(Long userId,
                                      int page,
                                      int size) {
        final Pageable pageable = PageRequest.of(page, size);

        return joinLogRepository.queryByCreatorIdOrReceiveIdOrderByStatus(userId, pageable);
    }
}
  • 接口JoinLogRepository.java
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

import java.util.List;
import java.util.Set;

/**
 * @author xxx
 */
public interface JoinLogRepository extends JpaRepository<JoinLog, Long>,
        JpaSpecificationExecutor<JoinLog> {
    /**
     * 分页查询邀请列表.
     *
     * @param userId
     * @param pageable
     * @return
     */
    Page<JoinLog> queryByCreatorIdOrReceiveIdOrderByStatus(Long userId, Pageable pageable);
}

  • 实现类JpaJoinLogRepository.java
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

/**
 * @author xxx
 */
public interface JpaJoinLogRepository extends JoinLogRepository {

    /**
     * 查询我待处理的和发送的工单.
     * <p>
     * 先按状态排序,未处理的排前面
     * 再按处理人排序,非自己的排前面
     * 最后按修改时间倒序
     * </p>
     *
     * @param userId
     * @param pageable
     * @return
     */
    @Override
    @Query("sql语句")
    Page<JoinLog> queryByCreatorIdOrReceiveIdOrderByStatus(@Param("userId") Long userId,
                                                           @Param("pageable") Pageable pageable);
}

四、复杂排序

要实现上面的复杂排序,本来只需要把sql语句转换为jql语句。

但是,我们的order by 条件在拼接的时候,不支持小括号。

举例说明:
最上面的sql语句也可以这么写:

select jl.*
from join_log jl  where (jl.creator_id = 1192660 or jl.receive_id  = 1192660) and jl.deleted = 0 
order by if(jl.status=0, 0, 1) asc,
 if(jl.creator_id=1192660, 0, 1) desc,  
 jl.modified_date desc 
 limit 0,10;

但是,在你试图转换为jql的时候,则会报错,变成了下面的错误sql语句。

select jl.*
from join_log jl  where (jl.creator_id = 1192660 or jl.receive_id  = 1192660) and jl.deleted = 0 
order by if() asc,
 if() desc,  
 jl.modified_date desc 
 limit 0,10;

所以,我们放弃if语句,换为case when语句。正确的jql语句见下:

@Query("select j from JoinLog j where (j.creatorId=:userId or j.receiveId=:userId) and j.deleted=0 " +
            " order by " +
            " case when j.status=0 then 0 else 1 end asc, " +
            " case when j.creatorId=:userId then 0 else 1 end desc," +
            " j.modifiedDate desc")

五、总结

分页和排序,作为查询的基本需求,本文以一个具体的示例,给你演示了从原生sql到hql的过程,最后使用case/when替换if实现了分类排序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1180865.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云尘靶场-Tr0ll-vulhub

直接fscan扫描 发现这里有一个ftp 我们等等看 首先去nmap扫描端口 nmap -A -p- 172.25.0.13 --unprivileged 这里使用wsl ftp ssh 和80 然后我们继续继续目录扫描 dirb 出来没什么用处 所以我们继续去看 流量包 流量包分析 首先看tcp ->分析->追踪流 这里是f…

什么是Kubernetes RBAC?为什么需要它?

目录 什么是Kubernetes RBAC? 如何启用Kubernetes RBAC 1.服务帐户 2.角色和集群角色 3.角色绑定和集群角色绑定 Kubernetes RBAC的好处 1.适当的授权 2.职责分离 3.100%遵守法规 Kubernetes RBAC的缺点 企业软件开发工具 什么是Kubernetes RBAC? 当组织开始走上…

英国最值得参观的十大博物馆介绍

目前&#xff0c;到英国从事访问交流及博士后研究的学者越来越多&#xff0c;而英国一向以厚重的历史人文以及精彩绝伦的艺术著称&#xff0c;在这样一个有着浓厚历史沉淀的国家&#xff0c;自然最不缺的就是博物馆了&#xff0c;在学习工作的闲暇&#xff0c;可以去参观体验一…

C语言求解有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?

完整代码&#xff1a; /*有一对兔子&#xff0c;从出生后第3个月起每个月都生一对兔子&#xff0c;小兔子长到第三个月后每个月 又生一对兔子&#xff0c;假如兔子都不死&#xff0c;问每个月的兔子总数为多少&#xff1f; 程序分析&#xff1a; 兔子的规律为数列1,1,2,3,5,8…

AI智能公文写作助手“文山会海“

公文写作痛点 没思路&#xff0c;公文写作无从下手公文类型繁多&#xff0c;一时难以全面掌握公文内容组织难度大&#xff0c;不易清晰、有逻辑的进行表达时间紧任务急&#xff0c;往往需要在有限的时间内完成大量写作工作反复修改优化&#xff0c;需满足更多新要求&#xff0…

WordPress 企业一号wp主题企业建站模板V1.2.2开心版

模板简介&#xff1a; 企业一号是一款由主题巴巴团队原创设计开发的WordPress企业主题。这款主题配备了强大的可视化、模块化的页面设计功能&#xff08;页面构建器&#xff09;&#xff0c;让您通过添加不同的设计模块和配置模块选项就可以设计出各种丰富多彩的页面。主题还集…

信号发送与处理-上

问题 按下 Ctrl C 后&#xff0c;命令行中的前台进程会被终止。为什么&#xff1f;&#xff1f;&#xff1f; 什么是信号&#xff1f; 信号是一种 "软件中断"&#xff0c;用来处理异步事件 内核发送信号到某个进程&#xff0c;通知进程事件的发送事件可能来自硬件…

③【操作表数据】MySQL添加数据、修改数据、删除数据

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ MySQL添加数据、修改数据、删除数据 &#x1f…

渗透测试学习day2

文章目录 连接靶机靶机&#xff1a;Fawn 解题过程Task 1Task 2Task 3Task 4Task 5Task 6Task 7Task 8Task 9Task 10Task 11Task 12 总结 连接靶机 详细过程可参考day1 靶机&#xff1a;Fawn 难度&#xff1a;very easy &#xff08;ftp服务的靶机&#xff09; 解题过程 T…

单链表(1)

前面的顺序表是顺序存储&#xff08;类似于数组&#xff09;&#xff0c;下面的链表是链式存储。物理是否相邻就看其存储地址&#xff08;格子&#xff09;是否相邻挨在一起。逻辑是否相邻看其前驱后继。 例如上面3个数据 如果存在顺序表中&#xff0c;那就是100的后继是200,2…

网络测试工具—— iperf2 安卓APK 下载 及简单使用

网络测试工具—— iperf2 安卓APK 下载 及简单使用 前言一、iperf2是什么&#xff1f;二、使用步骤附上help中命令截图翻译总结 前言 项目上有一款安卓车机加载局域网图片加载非常慢&#xff0c;所以需要测试一个安卓车机设备的带宽&#xff0c;经过调研后使用到了iperf2。 一…

【Android】Debug时禁用主线程ANR限制

ANR全称Application Not Response&#xff0c;指主线程超过5s无响应&#xff0c;应用会自动退出 由于这个线程&#xff0c;如果我们给主线程加了断点&#xff0c;就会触发ANR&#xff0c;导致调试时应用退出 这样调试起来会非常麻烦&#xff0c;其实对于Debug应用&#xff0c…

解决springboot整合websocket、redis、openfeign,redisTemplate,openfeign的类无法注入的问题

在部分业务中&#xff0c;我们需要使用长连接&#xff0c;我们可以使用http长连接或者websocket&#xff0c;在springboot作为后端的框架中&#xff0c; 可以借用的技术是&#xff08;netty&#xff0c;websocket&#xff09; 版本如下 软件版本号jdk21springboot 3.1.5 spri…

企业微信开启接收消息+验证URL有效性

企业微信开启接收消息验证URL有效性 &#x1f4d4; 千寻简笔记介绍 千寻简笔记已开源&#xff0c;Gitee与GitHub搜索chihiro-notes&#xff0c;包含笔记源文件.md&#xff0c;以及PDF版本方便阅读&#xff0c;且是用了精美主题&#xff0c;阅读体验更佳&#xff0c;如果文章对…

[极客大挑战 2019]Upload 1

题目环境&#xff1a; 根据题目和环境可知此题目是一道文件上传漏洞 编写一句话木马脚本<?php eval($_POST[shell]);?>将脚本文件更改为jpg图片文件我这里是flag.jpg上传文件并burpsuite抓包Repeater重放 报错一句话木马里面有<?字符 换一种一句话木马继续编写木马…

iOS实现代码混淆

​ 目录 前言 ipaguard界面概览 ipaguard启动界面 ipaguard代码混淆界面 资源文件混淆界面 重签名界面 前言 本文章向大家介绍iOS实现代码混淆&#xff0c;主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项&#xff0c;具有一定的参考价值&#xff0c;需…

高德地图设置电子围栏

高德地图设置电子围栏 需求效果图代码实现 需求 给地图上人员锚点设置围栏区域&#xff0c;如果在此区域内则是在线状态&#xff0c;不在此区域内则是离线状态 效果图 双击可编辑或清除当前围栏 代码实现 前端实现区域框选&#xff1a; //引入高德地图sdk"amap/amap…

Python语言高级实战-内置函数super()的使用之类的多继承(附源码和实现效果)

实现功能 super()函数的调用顺序是按照方法解析顺序&#xff08;Method Resolution Order, MRO&#xff09;来确定的。MRO 是一个确定继承顺序的算法&#xff0c;它使用 C3 线性化算法来避免潜在的方法冲突。Python会根据继承顺序自动计算 MRO&#xff0c;我们只需要使用 supe…

人人都会的 Blazor —— 1.3 项目结构

项目结构 使用 Visual Studio 2022 创建 Blazor 项目。 在搜索框中输入【blazor】关键字,将列出以下已经存在的项目模板: Blazor Server App:基于 Blazor Server 托管模型的项目,并建立一些示例代码和组件;Blazor WebAssembly App:基于 Blazor WebAssembly 托管模型的项…

CSS 外边距、填充、分组嵌套、尺寸

一、CSS 外边距&#xff1a; CSS margin&#xff08;外边距&#xff09;属性定义元素周期的空间。margin清除周围的&#xff08;外边框&#xff09;元素区域。margin没有背景颜色&#xff0c;是完全透明的。margin可以单独改变元素的上、下、左、右边距&#xff0c;也可以一次改…