1. 程式人生 > >一對多分頁的SQL到底應該怎麼寫?

一對多分頁的SQL到底應該怎麼寫?

![](https://img2020.cnblogs.com/other/1739473/202006/1739473-20200623100904075-1973408267.jpg) ## 1. 前言 **MySQL**一對多的資料分頁是非常常見的需求,比如我們要查詢商品和商品的圖片資訊。但是很多人會在這裡遇到分頁的誤區,得到不正確的結果。今天就來分析並解決這個問題。 ## 2. 問題分析 我們先建立一個簡單商品表和對應的商品圖片關係表,它們之間是一對多的關係: ![一對多關係](https://img2020.cnblogs.com/other/1739473/202006/1739473-20200623100904279-231893267.png) 然後我分別寫入了一些商品和這些商品對應的圖片,通過下面的左連線查詢可以看出它們之間具有明顯的一對多關係: ```sql SELECT P.PRODUCT_ID, P.PROD_NAME, PI.IMAGE_URL FROM PRODUCT_INFO P LEFT JOIN PRODUCT_IMAGE PI ON P.PRODUCT_ID = PI.PRODUCT_ID ``` ![所有的一對多結果](https://img2020.cnblogs.com/other/1739473/202006/1739473-20200623100904486-1769381241.png) 按照傳統的思維我們的分頁語句會這麼寫: ```xml ``` 當我按照預想傳入了`(0,2)`想拿到前兩個產品的資料,結果並不是我期望的: ``` 2020-06-21 23:35:54.515 DEBUG 10980 --- [main] c.f.m.mappers.ProductInfoMapper.page : ==> Preparing: SELECT P.PRODUCT_ID, P.PROD_NAME,PI.IMAGE_URL FROM PRODUCT_INFO P LEFT JOIN PRODUCT_IMAGE PI ON P.PRODUCT_ID = PI.PRODUCT_ID limit ?,? 2020-06-21 23:35:54.541 DEBUG 10980 --- [main] c.f.m.mappers.ProductInfoMapper.page : ==> Parameters: 0(Long), 2(Long) 2020-06-21 23:35:54.565 DEBUG 10980 --- [main] c.f.m.mappers.ProductInfoMapper.page : <== Total: 2 page = [ProductDTO{productId=1, prodName='杯子', imageUrls=[http://asset.felord.cn/cup1.png, http://asset.felord.cn/cup2.png]}] ``` 我期望的兩條資料是杯子和筆記本,但是結果卻只有一條。原來當一對多對映時結果集會按照多的一側進行輸出(期望4條資料,實際上會有7條),而前兩條展示的只會是杯子的資料(如上圖),合併後就只有一條結果了,這樣分頁就對不上了。那麼如何才能達到我們期望的分頁效果呢? ## 3. 正確的方式 > **正確的思路是應該先對主表進行分頁,再關聯從表進行查詢。** 拋開框架,我們的**SQL**應該先對產品表進行分頁查詢然後再左關聯圖片表進行查詢: ```sql SELECT P.PRODUCT_ID, P.PROD_NAME, PI.IMAGE_URL FROM (SELECT PRODUCT_ID, PROD_NAME FROM PRODUCT_INFO LIMIT #{current},#{size}) P LEFT JOIN PRODUCT_IMAGE PI ON P.PRODUCT_ID = PI.PRODUCT_ID ``` 這種寫法的好處就是通用性強一些。但是**MyBatis**提供了一個相對優雅的路子,思路依然是開頭所說的思路。只不過我們需要改造上面的**Mybatis XML**配置: ```xml ``` ## 4. 總結 大部分情況下分頁是很容易的,但是一對多還是有一些小小的陷阱的。一旦我們瞭解了其中的機制,也並不難解決。當然如果你有更好的解決方案可以留言討論,集思廣益。多多關注:**碼農小胖哥**,獲取更多開發技巧。 `關注公眾號:Felordcn 獲取更多資訊` [個人部落格:https://felord.cn](https://fe