mybatis Result Maps對結果分組1--一對多 mybatis3 autoMappingBehavior (譯)如何在sql中選取每一組的第一行/最後行/前幾行 (譯)如何在sql中選取

轉載請註明: TheViper http://www.cnblogs.com/TheViper html

一對多的關係,好比文章和評論,這時須要展現文章和評論,並按文章分組。不少時候,頁面只顯示評論數,若是用戶要看具體評論,就要點擊評論數的連接。java

好比微博sql

知乎mongodb

若是必定要在展現文章(或微博)時,顯示前幾條評論該怎麼作呢?(這裏不討論mongodb)數據庫

一個常見的作法是對一方,外鏈接多方,一併取出,而後手工遍歷分組。apache

這裏仍是以文章評論和回覆爲例mybatis

評論表app

回覆表post

兩個表的id字段分別表示評論的用戶id和回覆的用戶id,articlereplay表的comment_id是外鍵.另外還有個user表(id,name)。ui

外鏈接

        SELECT articlecomment.articlecomment_id,articlecomment.commenttime,articlecomment.commentcontent,articlecomment.id as commentuser_id
        ,articlereply.articlereply_id,articlereply.replytime,articlereply.replycontent,articlereply.id as replyuser_id
        ,u1.name AS comment_user,u2.name AS reply_user FROM articlecomment 
        LEFT JOIN articlereply ON articlereply.comment_id=articlecomment.articlecomment_id INNER JOIN USER AS u1 ON u1.id=articlecomment.id 
        INNER JOIN USER AS u2 ON u2.id=articlereply.id ORDER BY commenttime DESC,replytime DESC    

實際上這裏不用寫代碼遍歷結果,進行分組。用mybatis的resultmap就能夠很優雅的幫咱們按評論分好組。

ArticleComment類

public class ArticleComment {
    private int articlecomment_id;
    private String commentcontent;
    private String commenttime;
    private User user;
    private Article article;
    private List<ArticleReply> replys;
        //getter,setter  
}

ArticleReply類

public class ArticleReply {
    private int articlereply_id;
    private String replycontent;
    private String replytime;
    private User user;
        //setter,getter
}

resultmap

    <resultMap id="ArticleCommentResult" type="ArticleComment">
        <id property="articlecomment_id" column="articlecomment_id" />
        <association property="user" javaType="User">
               <id property="id" column="commentuser_id"/>
            <result property="name" column="comment_user"/>
        </association>
        <collection property="replys" ofType="ArticleReply">
            <association property="user" javaType="User">
                <id property="id" column="replyuser_id" />
                <result property="name" column="reply_user"/>
            </association>
        </collection>
    </resultMap>

從「一」(articlecomment)那邊取"多"(articlereply).注意,<association>要放到<collection>前面,不然報錯。

org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 16; columnNumber: 14; 元素類型爲 "resultMap" 的內容必須匹配 "(constructor?,id*,result*,association*,collection*,discriminator?)"。

pojo的類屬性名儘可能和數據庫相應表的字段名一致,參見本屌的文章mybatis3 autoMappingBehavior

另外這裏的兩個表都內鏈接User表獲取用戶名,所以在sql中分別重命名爲comment_user,reply_user.id也同樣。這裏重命名爲commentuser_id,replyuser_id.這就須要用<result>調整,使被重命名的字段和pojo類屬性名相對應。

效果

問題又來了,上面是把回覆所有選出來了,實際需求多是隻選取離當前時間最近的5條回覆,若是用戶想看到更多回復,就須要點「加載更多」。這又該怎麼作?

參見本屌翻譯的(譯)如何在sql中選取每一組的第一行/最後行/前幾行

        SELECT articlecomment.*,articlereply1.* FROM articlecomment 
        LEFT JOIN 
        (SELECT *
        FROM articlereply
        WHERE (
               SELECT COUNT(*) FROM articlereply AS f
               WHERE f.comment_id = articlereply.comment_id AND f.replytime >= articlereply.replytime
              ) <= 2
         ) AS articlereply1
         ON articlereply1.comment_id=articlecomment.articlecomment_id ORDER BY articlereply1.replytime DESC

left join一個子查詢,從articlereply表中選出每組離當前世界最近的2條回覆,其餘的和前面的外鏈接查詢同樣。

另外,若是用(譯)如何在sql中選取每一組的第一行/最後行/前幾行裏面提到的user variables方法,實際上就是把上面sql裏面left join後articlereply子查詢寫成user variables形式。但這就有個問題,每組的row_number會依次遞增,而咱們須要的是order by replytime desc,和row_number的順序相反.

結果

上面查詢沒有對row_number進行過濾,這時若是WHERE x.row_number<=2,獲得的結果與咱們想要的相反。

這時很容易想到把row_number的順序反過來,不過本屌不知道怎麼修改if(@type = type, @num + 1, 1)。沒辦法只有用子查詢了。

SELECT *
FROM (
   SELECT articlereply.*,
      @num := IF(@type =comment_id, @num + 1, 1) AS row_number,
      @type := comment_id AS dummy
   FROM articlereply 
) AS X WHERE x.row_number>=(SELECT COUNT(*) FROM articlereply WHERE articlereply.comment_id=x.comment_id
  GROUP BY articlereply.comment_id)-1

結果

相關文章
相關標籤/搜索