在Spring Data JPA中使用@Query注解

目錄

  • 前言
  • 示例
    • 簡單示例
    • 只查詢部分字段,映射到一個實體類中
    • 只查詢部分字段時,也可以使用List<Object[]>接收返回值
    • 再復雜一些

前言

在以往寫過幾篇spring data jpa相關的文章,分別是
Spring Data JPA 使用JpaSpecificationExecutor實現多條件查詢(分頁查詢和非分頁查詢)
Spring Data JPA實現分頁多條件查詢2

都是通過代碼而不是sql來完成查詢的,但是在做復雜情況的查詢時,難免會用到@Query寫sql語句。

示例

簡單示例

在@Query中用:paramName標識參數,再用@Param來指定方法參數與查詢語句中的參數之間的映射關系。
例如:

@Query("select r from RelationDO r where r.indexCode in :idList")
List<RelationDO> findByIdListIn(@Param("idList") Collection<String> idList);

只查詢部分字段,映射到一個實體類中

注意類的路徑寫完整

@Query("SELECT new com.xxx.service.impl.bo.RecordBO(e.code, e.day, e.total, e.success, e.fail, e.app) " +"FROM RecordDO e " +"WHERE e.code = :code AND e.day = :day " +"AND e.app in :appCodes")
List<RecordBO> findCalendarDetail(@Param("code") String code,@Param("day") String day,@Param("appCodes") List<String> appCodes);

這里為什么映射了一個新的BO出來呢… 是RecordDO中有一個id字段,在實體類中添加了@Id注解(實體必須有@Id,不然會報錯),這個id字段本來設計的是不會重復的,但是后續經過一些改動,它在某些情況下會重復了,這個時候就會有一個問題,我直接select整個RecordDO,id字段重復的它會當成同一條記錄(不確定為什么,但是實際跑出來確實是這樣),但我又不想再去改表結構,因此這里我select的時候直接省略了id字段,就正常了。(可能不是一個很好的解決方案,但是確實是可以這么做的)
只查詢部分字段在表字段較多,所需字段比較少的時候還是可以用的。

只查詢部分字段時,也可以使用List<Object[]>接收返回值

例如我現在需要用code和month查出這么一個結果:

[{"day":"20240601","result":[{"rate": 98.77"app": "0001"},{"rate": 95.32"app": "0002"}]},{"day":"20240602","result":[{"rate": 95.65"app": "0001"},{"rate": 96.89"app": "0002"}]},……
]

也就是說要把月份中的每一天抽取出來,再在下面放每個app對應的明細
這個時候寫sql:

@Query("SELECT e.day, e.app, e.success, e.total" +"FROM RecordDO e " +"WHERE e.code = :code AND SUBSTRING(e.day, 1, 6) = :month AND e.total > 0")
List<Object[]> findByMonth(@Param("code") String code,@Param("month") String month);

調用上述方法后封裝返回數據:

List<CalendarBO> calendarBOS = Lists.newArrayList();
List<Object[]> resultList = recordRepository.findByMonth(code,month);if (!CollectionUtils.isEmpty(resultList)){for (Object[] result : resultList) {String day = (String) result[0];String app = (String) result[1];Integer success = (Integer) result[2];Integer total = (Integer) result[3];double rate = (double) success * 100 / total ;double roundedRate = Math.round(rate * 100.0) / 100.0;CalendarBO.Result result = CalendarBO.Result.builder().app(app).rate(roundedRate).build();// 組裝返回內容Optional<CalendarBO> optionalBO = calendarBOS.stream().filter(bo -> bo.getDay().equals(day)).findFirst();// 該日期值不存在則創建 存在則添加不同app的記錄if (!optionalBO.isPresent()) {CalendarBO calendarBO = CalendarBO.builder().day(day).result(Collections.singletonList(result)).build();calendarBOS.add(calendarBO);}else {CalendarBO calendarBO = optionalBO.get();List<CalendarBO.Result> results = calendarBO.getResult();results.add(result);calendarBO.setAssessResult(results);}}
}

再復雜一些

通過beginMonth、endMonth和appCodes篩選,需要返回的數據格式如下
這里的pass是有一個標準rate,當data中success/total(rate) > 標準rate時單項視為pass,而total中的total則代表該月份區間共統計次數。

{"total": [{"total": 13,"pass": 13,"app": "0001"},{"total": 13,"pass": 12,"app": "0002"}],"data": [{"code": "101","month": 202406,"result": [{"total": 13,"success": 13,"rate": 100,"app": "0001"},{"total": 12,"success": 11,"rate": 92,"app": "0002"}]},{"code": "102","month": 202406,"result": [{"total": 15,"success": 15,"rate": 100,"app": "0001"}]},……]
}

此時的sql:

@Query("SELECT e.code, e.app, SUBSTRING(e.day, 1, 6), COUNT(e.statId), " +"SUM(CASE WHEN (CAST(e.success AS double) / e.total) >= :rate THEN 1 ELSE 0 END) " +"FROM RecordDO e " +"WHERE e.code = :code" +"    AND SUBSTRING(e.day, 1, 6) BETWEEN :beginMonth AND :endMonth " +"    AND ((:appCodes) IS NULL OR e.app IN (:appCodes)) AND e.total > 0 " +"GROUP BY e.code, e.app, SUBSTRING(e.day, 1, 6)")
List<Object[]> findByCodeGroupBy(@Param("code") String code,@Param("beginMonth") String beginMonth,@Param("endMonth") String endMonth,@Param("appCodes") List<String> appCodes,@Param("rate") Double rate);

這樣就直接把總數和pass的計數給取出來了(statId和總數可以對應)
調用上述方法后封裝返回數據,和之前基本一致:

// 根據分類計算總數的映射
Map<String, Integer> totalCounts = new HashMap<>();
Map<String, Integer> passCounts = new HashMap<>();
//返回的明細對象
List<DataBO> dataList = new ArrayList<>();//假設已獲取到code和標準rate的對應關系passRate
for (Map.Entry<String, Double> entry : passRate.entrySet()) {List<Object[]> resultList = recordRepository.findByCodeGroupBy(entry.getKey(), reqBO.getBeginMonth(),reqBO.getEndMonth(), reqBO.getAppCodeList(), entry.getValue());if (CollectionUtils.isEmpty(resultList)) {continue;}for (Object[] result : resultList) {String code = (String) result[0];String app = (String) result[1];String month = (String) result[2];Long totalLong = (Long) result[3];String total = totalLong.toString();Long successLong = (Long) result[4];String success = successLong.toString();double rateDouble = Double.parseDouble(success) / Double.parseDouble(total);String rate = String.format("%.2f", rateDouble * 100);DataBO.Result result = DataBO.Result.builder().total(total).success(success).rate(rate).app(app).build();//查看dataList中是否該編碼和月份的數據已存在 不存在則新建 存在則獲取DataBO data = dataList.stream().filter(a -> a.getCode().equals(code) && a.getMonth().equals(month)).findFirst().orElseGet(() -> {DataBO newAccount = new DataBO();newAccount.setCode(code);newAccount.setMonth(month);accountList.add(newAccount);return newAccount;});if (data.getResult() == null) {data.setResult(Lists.newArrayList());}data.getResult().add(result);// 更新統計totalCounts.put(app, totalCounts.getOrDefault(app, 0) + Integer.parseInt(total));passCounts.put(app, passCounts.getOrDefault(app, 0) + Integer.parseInt(success));}
}
//組裝統計類
totalCounts.entrySet().stream().map(entry -> {String app = entry.getKey();int total = entry.getValue();int pass = passCounts.getOrDefault(app, 0);TotalCountBO totalCount = new TotalCountBO();totalCount.setAppCode(app);totalCount.setTotal(String.valueOf(total));totalCount.setPass(String.valueOf(pass));return totalCount;}).collect(Collectors.toList());return RespBO.builder().data(dataList).total(totalCounts).build();

匆忙所寫,不確定有沒有問題,有的話聯系我~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/38887.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/38887.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/38887.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python 筆試面試八股(自用版~)

1 解釋型和編譯型語言的區別 解釋是翻譯一句執行一句&#xff0c;更靈活&#xff0c;eg&#xff1a;python; 解釋成機器能理解的指令&#xff0c;而不是二進制碼 編譯是整個源程序編譯成機器可以直接執行的二進制可運行的程序&#xff0c;再運行這個程序 比如c 2 簡述下 Pyth…

運維鍋總詳解RocketMQ

本文嘗試從Apache RocketMQ的簡介、主要組件及其作用、3種部署模式、Controller集群模式工作流程、最佳實踐等方面對其進行詳細分析。希望對您有所幫助&#xff01; 一、Apache RocketMQ 簡介 Apache RocketMQ 是一個開源的分布式消息中間件&#xff0c;由阿里巴巴集團開發并…

祝賀《華為戰略管理法:DSTE實戰體系》被《中國企業家》雜志評為企業家枕邊書50本之一(宏觀戰略類書籍)

祝賀《華為戰略管理法&#xff1a;DSTE實戰體系》被《中國企業家》雜志評為企業家枕邊書50本之一 2024年4月23日&#xff08;周二&#xff09;下午13:00&#xff0c;《中國企業家》雜志如期舉辦“每天都是讀書日”線下活動。 《中國企業家》雜志攜手商界大咖共同推選50本枕邊書…

Vue.js中的計算屬性

Vue.js中的計算屬性&#xff08;computed properties&#xff09;是用于聲明響應式依賴的屬性。它們會根據它們的依賴進行緩存&#xff0c;并且只有在相關依賴發生改變時才會重新求值。這使得它們非常適合用來處理復雜邏輯和數據處理。 基本用法 在Vue實例中&#xff0c;可以…

鐳速實現AD域集成助力企業文件安全傳輸管控

在當今這個信息量爆炸擴張的年代&#xff0c;企業數據宛如一座蘊藏無限價值的寶庫&#xff0c;它不僅是企業核心競爭力的載體&#xff0c;也成為了各種潛在風險的聚焦點。隨著數字化轉型步伐的加快&#xff0c;安全文件傳輸的管理控制顯得尤為重要&#xff0c;它構成了保護企業…

各類排序方法 歸并排序 擴展練習 逆序對數量

七月挑戰一個月重刷完Y總算法基礎題&#xff0c;并且每道題寫詳細題解 進度:(3/106) 歸并排序的思想也是分而治之 歸并優點&#xff1a;速度穩定,排序也穩定 排序也穩定&#xff08;數組中有兩個一樣的值&#xff0c;排序之后他們的前后順序不發生變化&#xff0c;我們就說…

Leetcode 2065. 最大化一張圖中的路徑價值(DFS / 最短路)

Leetcode 2065. 最大化一張圖中的路徑價值 暴力DFS 容易想到&#xff0c;從0點出發DFS&#xff0c;期間維護已經走過的距離&#xff08;時間&#xff09;和途徑點的權值之和&#xff0c;若訪問到0點則更新答案&#xff0c;若下一步的距離與已走過的距離和超出了maxTime&#…

oracle sql語句 排序 fjd = ‘0101‘ 排在 fjd = ‘0103‘ 的前面

要實現這個排序需求&#xff0c;你可以使用 CASE 表達式來自定義排序邏輯。假設你有一個表格名為 your_table&#xff0c;并且有一個字段 fjd 存儲類似 ‘0101’, ‘0103’ 這樣的值&#xff0c;你可以這樣編寫 SQL 查詢&#xff1a; SELECT * FROM your_table ORDER BY CASE …

專題六:Spring源碼之初始化容器BeanFactory

上一篇咱們通過一個例子介紹初始化容器上下文相關內容&#xff0c;并通過兩個示例代碼看到了Spring在設計階段為我預留的擴展點&#xff0c;和我們應該如何利用這兩個擴展點在Spring初始化容器上下文階段為我們提供服務。這一篇咱們接著往下看。 老這樣子下回到refresh方法上來…

第55期:MySQL 頻繁 Crash 怎么辦?

社區王牌專欄《一問一實驗&#xff1a;AI 版》全新改版歸來&#xff0c;得到了新老讀者們的關注。其中不乏對 ChatDBA 感興趣的讀者前來咨詢&#xff0c;表達了想試用體驗 ChatDBA 的意愿&#xff0c;對此我們表示感謝 &#x1f91f;。 目前&#xff0c;ChatDBA 還在最后的準備…

MSVCR120.DLL丟失的多種修復方法,助你快速解決dll問題

在日常生活和工作中&#xff0c;電腦已經成為我們不可或缺的工具。然而&#xff0c;在使用電腦的過程中&#xff0c;我們常常會遇到一些問題&#xff0c;其中之一就是電腦運行軟件時提示找不到msvcr120.dll。如果該文件缺失或損壞&#xff0c;可能會導致依賴它的應用程序無法啟…

高優先線程

你開發的時候有么有遇到過一個問題&#xff1a;服務器的一個服務線程過幾個小時斷連一次&#xff0c;斷連之后會馬上重連這種情況。這是由于CPU負載較高,線程調度時將處理數據的線程掛起了一段時間導致的。 因此&#xff0c;我有考慮到把cpu的核心進行分散開來&#xff0c;就類…

CesiumJS【Basic】- #042 繪制紋理線(Primitive方式)

文章目錄 繪制紋理線(Primitive方式)1 目標2 代碼2.1 main.ts3 資源文件繪制紋理線(Primitive方式) 1 目標 使用Primitive方式繪制紋理線 2 代碼 2.1 main.ts var start = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);var

【劍指Offer系列】68-二叉樹的最近公共祖先(哈希)

思路&#xff1a;使用map存儲每個節點的父節點&#xff0c;則兩個節點的最近公共祖先&#xff0c;即二者的最近父節點 1、中序遍歷二叉樹&#xff08;當前節點的下一個節點&#xff09; 2、記錄每個節點的父節點 3、列出p的族譜、q的族譜 4、尋找二者最近的祖先 class Soluti…

微信小程序畢業設計-英語互助系統項目開發實戰(附源碼+論文)

大家好&#xff01;我是程序猿老A&#xff0c;感謝您閱讀本文&#xff0c;歡迎一鍵三連哦。 &#x1f49e;當前專欄&#xff1a;微信小程序畢業設計 精彩專欄推薦&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python畢業設計…

PS系統教程31

調色之色階 調色與通道最基本的關系通道是記錄顏色最基本的信息有些圖片可以用通道去改變顏色信息的說明這些圖像是比較高級的PS是一款圖像合成軟件&#xff0c;在合成過程中需要處理大量素材&#xff0c;比如要用這些素材進行摳背景&#xff0c;就要用到圖層蒙版以及Alpha通道…

Qt編程技巧總結篇(2)-信號-槽-多線程(一)

文章目錄 Qt編程技巧總結篇&#xff08;2&#xff09;-信號-槽-多線程&#xff08;一&#xff09;信號與槽實例與應用 小結 Qt編程技巧總結篇&#xff08;2&#xff09;-信號-槽-多線程&#xff08;一&#xff09; 最近學習信號與槽以及多線程&#xff0c;非常有技術含量&#…

【詳解】RV1106移植opencv-mobile庫

文章目錄 前言一、燒入鏡像二、編譯項目1.創建項目文件 三、移植四、運行文件五、總結 前言 硬件&#xff1a;瑞芯微Rv1106【Luckfox Pro\Max Pico、網線一根、USB線、串口助手、攝像頭 軟件&#xff1a;ubuntu 20.4 編譯器&#xff1a;arm-rockchip830-linux-uclibcgnueabihf…

人工智能——常用數學基礎之線代中的矩陣

1. 矩陣的本質&#xff1a; 矩陣本質上是一種數學結構&#xff0c;它由按照特定規則排列的數字組成&#xff0c;通常被表示為一個二維數組。矩陣可以用于描述一組數據&#xff0c;或者表示某種關系&#xff0c;比如線性變換。 在人工智能中&#xff0c;矩陣常被用來表示數據集…

【單片機與嵌入式】stm32串口通信入門

一、串口通信/協議 &#xff08;一&#xff09;串口通信簡介 串口通信是一種通過串行傳輸方式在電子設備之間進行數據交換的通信方式。它通常涉及兩條線&#xff08;一條用于發送數據&#xff0c;一條用于接收數據&#xff09;&#xff0c;適用于各種設備&#xff0c;從微控制…