Mysql 게시판 카테고리별 상위 n개 조회 질문입니다. 0 2 2,734

by 신짱 [MySQL] [2019.01.18 17:47:59]


안녕하세요!

이번에 게시판으로 프로젝트를 만들어보고 있는데 막히는 쿼리가 있어서 질문드립니다.

먼저 게시판은 아래와 같이 통합테이블(카테고리로 구분)을 하나 만들었구요. 아래와 같습니다.

bno category title content hits writer created_dt updated_dt
1 공지사항 공지A 공지내용A 25 관리자 2019-01-05 2019-01-05
2 공지사항 공지B 공지내용B 9 관리자 2019-01-04 2019-01-04
3 자료실 자료A 자료내용A 10 관리자 2019-01-03 2019-01-03
4 문의 문의A 문의내용A 2 관리자 2019-01-03 2019-01-03
5 문의 문의B 문의내용B 4 관리자 2019-01-03 2019-01-03
6 자료실 자료B 자료내용B 30 관리자 2019-01-02 2019-01-02
7 공지사항 공지C 공지내용C 17 관리자 2019-01-02 2019-01-02
8 자료실 자료C 자료내용C 6 관리자 2019-01-01 2019-01-01
9 문의 문의C 문의내용C 3 관리자 2019-01-01 2019-01-01

이때 카테고리별로 상위(최근날짜순) n개의 데이터를 조회할려고 합니다.

 

만약, 카테고리별로 상위 2개의 데이터만 조회한다고 하면 아래와 같이 조회하고 싶습니다.

bno category title content hits writer created_dt updated_dt
1 공지사항 공지A 공지내용A 25 관리자 2019-01-05 2019-01-05
2 공지사항 공지B 공지내용B 9 관리자 2019-01-04 2019-01-04
3 자료실 자료A 자료내용A 10 관리자 2019-01-03 2019-01-03
6 자료실 자료B 자료내용B 30 관리자 2019-01-02 2019-01-02
4 문의 문의A 문의내용A 2 관리자 2019-01-03 2019-01-03
5 문의 문의B 문의내용B 4 관리자 2019-01-03 2019-01-03

 

구글링을 해보니까 mysql말고 다른 db는 partition? 뭐 그런걸 이용해서 할 수 있는데 mysql은 지원이 안되서

사용자정의변수를 사용하더라구요.. @rank := 이런 변수들이 들어가던데 사용자정의 변수를 사용하지 않고

카테고리별로 상위 n개의 게시물을 가져오고 싶습니다.

조언부탁드립니다.

by 마농 [2019.01.21 09:16:46]

정렬 기준으로 created_dt 를 사용해야 하는데 중복이 가능하므로 유니크한 bno 를 정렬기준으로 추가해야 합니다.
예시 자료의 bno 순서가 거꾸로 된것이 아닌가 생각되네요?
최신 등록 글의 bno 가 더 크다고 가정하고 작성했습니다.

WITH t AS
(
SELECT 9 bno, '공지사항' category, '공지A' title, '공지내용A' content, 25 hits, '관리자' writer, '2019-01-05' created_dt, '2019-01-05' updated_dt
UNION ALL SELECT 8, '공지사항', '공지B', '공지내용B',  9, '관리자', '2019-01-04', '2019-01-04'
UNION ALL SELECT 7, '자료실'  , '자료A', '자료내용A', 10, '관리자', '2019-01-03', '2019-01-03'
UNION ALL SELECT 6, '문의'    , '문의A', '문의내용A',  2, '관리자', '2019-01-03', '2019-01-03'
UNION ALL SELECT 5, '문의'    , '문의B', '문의내용B',  4, '관리자', '2019-01-03', '2019-01-03'
UNION ALL SELECT 4, '자료실'  , '자료B', '자료내용B', 30, '관리자', '2019-01-02', '2019-01-02'
UNION ALL SELECT 3, '공지사항', '공지C', '공지내용C', 17, '관리자', '2019-01-02', '2019-01-02'
UNION ALL SELECT 2, '자료실'  , '자료C', '자료내용C',  6, '관리자', '2019-01-01', '2019-01-01'
UNION ALL SELECT 1, '문의'    , '문의C', '문의내용C',  3, '관리자', '2019-01-01', '2019-01-01'
)
-- 1. mySQL 도 8.0 부터는 분석함수 지원됩니다.
SELECT *
  FROM (SELECT a.*
             , ROW_NUMBER() OVER(PARTITION BY category ORDER BY created_dt DESC, bno DESC) rn
          FROM t a
        ) a
 WHERE rn <= 2
;
-- 2. @변수 사용
SELECT *
  FROM (SELECT a.*
             , @rn := CASE WHEN category != @category THEN 1 ELSE @rn + 1 END rn
             , @category := category x
          FROM t a
             , (SELECT @category := '', @rn := 0) b
         ORDER BY category, created_dt DESC, bno DESC
        ) a
 WHERE rn <= 2
;
-- 3. Self Join
SELECT a.*
     , COUNT(b.bno) + 1 rn
  FROM t a
  LEFT OUTER JOIN t b
    ON a.category = b.category
   AND ( (a.created_dt < b.created_dt) OR
         (a.created_dt = b.created_dt AND a.bno < b.bno) )
 GROUP BY a.bno
HAVING COUNT(b.bno) < 2
;
-- 4. Exists
 SELECT *
  FROM t a
 WHERE NOT EXISTS (SELECT 1
                     FROM t b
                    WHERE a.category = b.category
                      AND ( (a.created_dt < b.created_dt) OR
                            (a.created_dt = b.created_dt AND a.bno < b.bno) )
                      AND EXISTS (SELECT 1
                                    FROM t c
                                   WHERE b.category = c.category
                                     AND ( (b.created_dt < c.created_dt) OR
                                           (b.created_dt = c.created_dt AND b.bno < c.bno) )
                                  )
                   )
;
-- 5. 카테고리별 Limit, Union
(SELECT * FROM t WHERE category = '공지사항' ORDER BY created_dt DESC, bno DESC LIMIT 2)
UNION ALL (SELECT * FROM t WHERE category = '자료실' ORDER BY created_dt DESC, bno DESC LIMIT 2)
UNION ALL (SELECT * FROM t WHERE category = '문의'   ORDER BY created_dt DESC, bno DESC LIMIT 2)
;

 


by 신짱 [2019.01.23 14:40:51]

아 예시에서 bno를 거꾸로 작성했네요ㅎㅎ;;

상세한 답변 감사합니다!!

많은 도움이 되었습니다. 좋은하루 되세요 :)

 

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입