TIL

230320 [SQL, Spring] (페이징 처리)

하차모 2023. 3. 20. 17:46

1. 기본 세팅

  한 페이지에 보여지는 게시글 수 = 10개

  한 번에 보여지는 페이지 수 = 5개

  +) 등록 최신순으로 조회

ex)            1 2 3 4 5 다음

         이전 6 7 8 9 10 다음

         이전 11 12

 

2. ROWNUM을 이용한 쿼리 작성

  ROWNUM은 오라클에서 지원하는 가상 컬럼으로, 쿼리의 결과에 가상으로 1번부터 순번을 붙인다.

  페이징 처리를 위해 게시글에 ROWNUM으로 순번을 매긴 후, 범위를 지정하여 해당 페이지에 보여줄 게시글만 가져올 수 있다.

SELECT BOARD_NUM
    , BOARD_TITLE
    , BOARD_WRITER
    , TO_CHAR(REG_DATE, 'YYYY-MM-DD') AS REG_DATE
    , READ_CNT
    , ROWNUM
FROM SPRING_BOARD
WHERE ROWNUM >= 1 AND ROWNUM <= 10
ORDER BY BOARD_NUM DESC;

  하지만 다음과 같이 조회했을 때 ROWNUM이 순서대로 붙지 않고 뒤죽박죽인 것을 볼 수 있는데, 이는 ROWNUM의 실행순서 때문이다.

  ** ROWNUM 실행 순서 : SELECT한 쿼리에 ROWNUM이 지정된 후 ORDER BY로 정렬된다.

SELECT BOARD_NUM
    , BOARD_TITLE
    , BOARD_WRITER
    , REG_DATE
    , READ_CNT
    , ROWNUM ROW_NUM
FROM 
(
    SELECT BOARD_NUM
        , BOARD_TITLE
        , BOARD_WRITER
        , TO_CHAR(REG_DATE, 'YYYY-MM-DD') AS REG_DATE
        , READ_CNT
    FROM SPRING_BOARD
    ORDER BY BOARD_NUM DESC
)
WHERE ROWNUM >= 1 AND ROWNUM <= 10;

  이럴 때는 ORDER BY로 정렬한 쿼리를 FROM절에 넣어 가져온 후에 SELECT로 다시 감싸 순번을 붙이면 된다.

  +) FROM절에 서브쿼리를 삽입하여 새로운 테이블처럼 사용하는 것을 인라인 뷰라고 한다.

 

SELECT BOARD_NUM
    , BOARD_TITLE
    , BOARD_WRITER
    , REG_DATE
    , READ_CNT
    , ROWNUM ROW_NUM
FROM 
(
    SELECT BOARD_NUM
        , BOARD_TITLE
        , BOARD_WRITER
        , TO_CHAR(REG_DATE, 'YYYY-MM-DD') AS REG_DATE
        , READ_CNT
    FROM SPRING_BOARD
    ORDER BY BOARD_NUM DESC
)
WHERE ROWNUM >= 11 AND ROWNUM <= 20;

하지만 ROWNUM을 11부터 조회했을 때 아무 데이터도 조회되지 않는데, ROWNUM은 임시 행번호이기 때문에 무조건 1부터 붙기 때문이다. 특정 행번호를 지정해 조회하고 싶다면 한 번 더 SELECT 절로 감싸 조회해야 한다.

SELECT BOARD_NUM
    , BOARD_TITLE
    , BOARD_WRITER
    , REG_DATE
    , READ_CNT
    , ROW_NUM
FROM (
        SELECT BOARD_NUM
        , BOARD_TITLE
        , BOARD_WRITER
        , REG_DATE
        , READ_CNT
        , ROWNUM ROW_NUM
        FROM (
                SELECT BOARD_NUM
                    , BOARD_TITLE
                    , BOARD_WRITER
                    , TO_CHAR(REG_DATE, 'YYYY-MM-DD') AS REG_DATE
                    , READ_CNT
                FROM SPRING_BOARD
                ORDER BY BOARD_NUM DESC
        )
)
WHERE ROW_NUM >= 11 AND ROW_NUM <= 20;

 

 

3. 쿼리가 완성되었으니, mapper 파일의 게시판 리스트 조회 select 태그로 삽입해준다.

<select id="getBoardList" resultMap="board">
    SELECT (SELECT COUNT(BOARD_NUM) FROM SPRING_BOARD) - ROW_NUM + 1 AS ROW_NUMBER
        , BOARD_NUM
        , BOARD_TITLE
        , BOARD_WRITER
        , REG_DATE
        , READ_CNT
        , ROW_NUM
        , REPLY_CNT
        , IS_PRIVATE
    FROM (
            SELECT BOARD_NUM
            , BOARD_TITLE
            , BOARD_WRITER
            , REG_DATE
            , READ_CNT
            , ROWNUM ROW_NUM
            , REPLY_CNT
            , IS_PRIVATE
        FROM 
        (
            SELECT BOARD_NUM
                , BOARD_TITLE
                , BOARD_WRITER
                , TO_CHAR(REG_DATE, 'YYYY-MM-DD') AS REG_DATE
                , READ_CNT
                , (SELECT COUNT(REPLY_NUM) 
                    FROM SPRING_REPLY
                    WHERE BOARD_NUM = SPRING_BOARD.BOARD_NUM) AS REPLY_CNT
                , IS_PRIVATE
            FROM SPRING_BOARD
            ORDER BY BOARD_NUM DESC
        )
    )
    WHERE ROW_NUM &gt;= #{startNum} AND ROW_NUM &lt;= #{endNum}
</select>

+) 게시글 번호 쿼리 추가 : 총 게시글 수 - 행번호 + 1

  ex) 50번 글 번호를 구할 경우 : 최신순으로 조회되기 때문에  (54 53 52 51 50) 글 번호는 5번이 되어야 함.

        -> 총 게시글 수 54개 - 50번 글 + 1 = 5번

(SELECT COUNT(BOARD_NUM) FROM SPRING_BOARD) - ROW_NUM + 1 AS ROW_NUMBER

+) xml 파일에서는 <,> 가 태그 기호로 인식되기 때문에 &lt;, &gt;로 표기해야 한다.