MySQL에서 특정 row 기준으로 위 아래 row 구하기
개발 작업 중 특히 게시판 같은 경우 이전글
, 다음글
을 노출하게 된다. PK 값을 기준으로 작거나 큰 것 중 하나를 택하면 너무도 쉽게 처리가 가능한데.. 실제에선 여러 정렬 옵션이 적용될 수 있기 때문에 단순하게 접근해서는 원하는 결과를 얻지 못할 수가 있다. 아래와 같은 구조의 테이블이 있을 때 po_posted
값을 기준으로 desc 정렬을 할 때 같은 날짜가 있을 경우 문제가 발생한다.
CREATE TABLE `cm_post` (
`po_id` int(11) NOT NULL,
`bo_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`po_lang` char(2) COLLATE utf8mb4_unicode_ci NOT NULL,
`po_subject` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`po_content` text COLLATE utf8mb4_unicode_ci NOT NULL,
`po_seo_url` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`po_link` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`po_ip` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`po_date` datetime NOT NULL,
`po_posted` date NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
위 테이블에서 SELECT po_id, po_subject, po_posted FROM cm_post WHERE bo_id = 'news' and po_lang = 'ko' order by po_posted desc, po_id desc;
처럼 실행하면 아래와 같이 표시가 된다.
위 이미지와 같이 po_posted
값이 같은 경우 예를 들어 po_id
값이 4인 게시글의 이전 글을 구하려면 po_posted < '2020-07-09
처럼 조건을 추가하면 된다. 하지만 값이 5이 게시글의 이전글은 4 이어야 하지만 위 조건에서는 11 이 구해질 것이다. 이것은 원하는 결과가 아니다. 이런 경우를 해결하기 위해 다른 접근 방법이 필요하다. 오랜 시간의 구글링 결과 특정 게시글의 row index
값을 구한 후 그 값을 기준으로 위 아래 row 를 구하면 해결이 된다는 것을 알았다. row 의 index 값은 아래와 같이 구할 수 있다.
select row from (select @rownum:=@rownum+1 row, a.* from `cm_post` a, (select @rownum:=0) r where bo_id = 'news' and po_lang = 'ko' order by po_posted desc, po_id desc) as post_with_rows where po_id = '5'
위 쿼리를 실행하면 2
라는 값을 얻게 된다. 이 값은 위 이미지에서 확인할 수 있는 값과 같다. 이제 위 아래 row를 구해야 하는데 이 때는 limit 적절하게 사용하면 된다. 먼저 이전 글을 구하려면 아래와 같은 쿼리를 실행하면 됩니다.
SELECT po_id, po_subject, po_posted FROM cm_post WHERE bo_id = 'news' and po_lang = 'ko' order by po_posted desc, po_id desc limit 2, 1;
다음글을 아래의 쿼리로 구할 수 있습니다.
SELECT po_id, po_subject, po_posted FROM cm_post WHERE bo_id = 'news' and po_lang = 'ko' order by po_posted desc, po_id desc limit 0, 1;
각각의 쿼리를 보면 row의 index
값을 기준으로 이전글은 동일한 값을 사용하면 되고 다음글을 index
값에서 2를 뺀 값을 사용하는 것을 알 수 있다. 문제 해결에 참고한 포스트에서는 join
을 이용해서 해결하는 방법도 있다고 하니 관심이 있다면 살펴보는 것도 좋을 것 같다. 다만 다음글을 구할 때 2를 빼게 되는데 이 경우 -1 이 될 수도 있기 때문에 if 문을 사용해서 예외 처리를 해줘야 한다. 그렇지 않으면 쿼리 실행에서 오류가 발생한다.