sitelink1 | |
---|---|
sitelink2 | |
sitelink3 | |
sitelink4 | |
sitelink5 | |
sitelink6 |
계층형(답변형) 게시판에서 최근 답변이 하단으로 배치되길 원해서 방법을 찾던 중
ASP로 설명된 소스가 있어 그것을 기반으로 정리 해봤습니다.
http://www.dotnetkorea.com/boardview.asp?BoardName=ServerScript&Num=186
최근 답변이 상단으로 가는것은 부모글의 STEP보다 큰 글들을 1칸씩 밀고(STEP+1)
현재 답변이 부모글 다음 STEP으로(부모STEP+1) 들어가기 때문에 위로 배치됩니다.
select * from BOARD
order by REF desc, STEP asc
NO REF STEP LVL SBJ
2 2 0 0 2
3 2 1 1 _2-1
1 1 0 0 1
위 상태에서 2번글에 답변을 달면
update BOARD
set STEP = STEP + 1
where REF = 2 --부모REF
and STEP > 0 --부모STEP
ref = 2 + 1 // 부모REF + 1
lvl = 0 + 1 // 부모STEP + 1
이런 방식으로 처리가 되므로 결과는 아래와 같이 상단으로 배치됩니다.
NO REF STEP LVL SBJ
2 2 0 0 2
4 2 1 1 _2-2
3 2 2 1 _2-1
1 1 0 0 1
이제 답변을 하단로 배치시키는 방법을 설명하겠습니다.
아래 상태가 원하는 형태이고 이 상태에서 설명합니다.
NO REF STEP LVL SBJ
2 2 0 0 2
3 2 1 1 _2-1
5 2 2 2 __2-1-1
7 2 3 3 ___2-1-1-1
4 2 4 1 _2-2
6 2 5 2 __2-2-1
1 1 0 0 1
위 상태에서 답변을 할때 배치될 위치를 찾아보면 두가지 형태로 구분됩니다.
2,4,6번글에 답변을 하면 6,1번글 사이에 배치되면 됩니다.
3,5,7번글에 답변을 하면 7,4번글 사이에 배치되면 됩니다.
조금 바꿔 말하면
2,4,6번글에 답변을 하면 마지막 STEP 다음으로 들어가면 됩니다.
3,5,7번글에 답변을 하면 4번글의 STEP으로 끼어 들어가면 됩니다.
코딩하는 식으로 설명하면
2,4,6번글에 답변을 하면 최대STEP에 +1한 후 현재STEP으로 세팅해서 등록하면 됩니다.
3,5,7번글에 답변을 하면 4번글의 STEP보다 크거나 같은 글들의 STEP을 +1하고
현재STEP을 4번글의 STEP으로 세팅해서 등록하면 됩니다.
이제 해결할게 2,4,6번글과 3,5,7번글을 구분하는 방법과 4번글 STEP을 찾을 수 있으면 되는데
아래 SQL으로 구분하고 찾을 수 있습니다.
select min(STEP) from BOARD
where REF = 부모REF
and STEP > 부모STEP
and LVL <= 부모LVL
이 쿼리 결과가 null이면 2,4,6번글 형태(맨 밑으로 가는)이고
null이 아니면 3,5,7번글 형태(중간에 끼어 들어가는)이며 결과가 4번글의 STEP이 됩니다.
step = 결과STEP;
if (step == null) then { // 맨 밑으로 가는 형태
select max(STEP) + 1
from BOARD
where REF = 부모REF
step = 결과STEP;
} else { // 중간에 끼어 들어가는 형태
update BOARD
set STEP = STEP + 1
where REF = 부모REF
and STEP >= step
}
lvl = 부모LVL + 1;
이렇게 처리 후 insert하면 하단으로 답변이 배치됩니다.
NO REF STEP LVL SBJ
2 2 0 0 2
3 2 1 1 _2-1
5 2 2 2 __2-1-1
7 2 3 3 ___2-1-1-1
4 2 4 1 _2-2
6 2 5 2 __2-2-1
1 1 0 0 1
4번글에 답변을 하면
NO REF STEP LVL SBJ
2 2 0 0 2
3 2 1 1 _2-1
5 2 2 2 __2-1-1
7 2 3 3 ___2-1-1-1
4 2 4 1 _2-2
6 2 5 2 __2-2-1
8 2 6 2 __2-2-2
1 1 0 0 1
3번글에 답변을 하면
NO REF STEP LVL SBJ
2 2 0 0 2
3 2 1 1 _2-1
5 2 2 2 __2-1-1
7 2 3 3 ___2-1-1-1
8 2 4 2 __2-1-2
4 2 5 1 _2-2
6 2 6 2 __2-2-1
1 1 0 0 1
삭제시 자식글이 있는지 체크나 자식글 모두 삭제에도 처음 SQL을 이용하면 됩니다.
NO REF STEP LVL SBJ
2 2 0 0 2
3 2 1 1 _2-1
5 2 2 2 __2-1-1
7 2 3 3 ___2-1-1-1
4 2 4 1 _2-2
6 2 5 2 __2-2-1
1 1 0 0 1
4번글의 자식글 목록
select min(STEP) from BOARD
where REF = 2 --4번REF
and STEP > 4 --4번STEP
and LVL <= 1 --4번LVL
결과 없음 : null
select * from BOARD
where REF = 2 --3번REF
and STEP > 4 --3번STEP
order by REF desc, STEP asc
결과 : 6번글
3번글의 자식글 목록
select min(STEP) from BOARD
where REF = 2 --3번REF
and STEP > 1 --3번STEP
and LVL <= 1 --3번LVL
결과 있음 : 4
select * from BOARD
where REF = 2 --3번REF
and STEP > 1 --3번STEP
and STEP < 4 --결과STEP
order by REF desc, STEP asc
결과 : 5,7번글
한가지 더 얘기하면 게시글목록에서 order by REF desc, STEP asc로 정렬을 하는데
REF, SET에 대한 인덱스를 잡고 신규글 등록할때 REF를 음수로 등록하면
order by REF asc, STEP asc가 가능하므로 쉽게 index scan을 할 수 있습니다.
기존방식
select * from BOARD
order by REF desc, STEP asc
NO REF STEP LVL SBJ
2 2 0 0 2
3 2 1 1 _2-1
5 2 2 2 __2-1-1
7 2 3 3 ___2-1-1-1
4 2 4 1 _2-2
6 2 5 2 __2-2-1
1 1 0 0 1
SELECT STATEMENT Optimizer Mode=CHOOSE
SORT ORDER BY
TABLE ACCESS FULL BOARD
음수방식
select * from BOARD
order by REF, STEP
NO REF STEP LVL SBJ
2 -2 0 0 2
3 -2 1 1 _2-1
5 -2 2 2 __2-1-1
7 -2 3 3 ___2-1-1-1
4 -2 4 1 _2-2
6 -2 5 2 __2-2-1
1 -1 0 0 1
SELECT STATEMENT Optimizer Mode=CHOOSE
TABLE ACCESS BY INDEX ROWID BOARD
INDEX FULL SCAN IX_BOARD
아래는 테스트한 테이블과 샘플데이터에 대한 SQL입니다.
CREATE TABLE BOARD
(
NO INT NOT NULL,
REF INT NOT NULL,
STEP INT DEFAULT 0 NOT NULL,
LVL INT DEFAULT 0 NOT NULL,
SBJ VARCHAR(100),
PRIMARY KEY (NO)
);
CREATE INDEX IX_BOARD ON BOARD (REF, STEP);
INSERT INTO BOARD (NO, REF, STEP, LVL, SBJ) VALUES (1, 1, 0, 0, '1');
INSERT INTO BOARD (NO, REF, STEP, LVL, SBJ) VALUES (2, 2, 0, 0, '2');
INSERT INTO BOARD (NO, REF, STEP, LVL, SBJ) VALUES (3, 2, 1, 1, '_2-1');
INSERT INTO BOARD (NO, REF, STEP, LVL, SBJ) VALUES (4, 2, 4, 1, '_2-2');
INSERT INTO BOARD (NO, REF, STEP, LVL, SBJ) VALUES (5, 2, 2, 2, '__2-1-1');
INSERT INTO BOARD (NO, REF, STEP, LVL, SBJ) VALUES (6, 2, 5, 2, '__2-2-1');
INSERT INTO BOARD (NO, REF, STEP, LVL, SBJ) VALUES (7, 2, 3, 3, '___2-1-1-1');
COMMIT;
이제 javaservice.net처럼 최근 답변이 아래로 가는 게시판을 만들어 보세요.