요르딩딩
계층구조 쿼리 & makeTree 본문
이번에는 폴더안의 폴더 또는 데이터를 포함하는 계층적인 트리를 만들어 보게되었습니다.
여기서의 요점!!!은
첫번째 테이블에서 계층적인 순서로 조회하기
두번째 조회한 리스트를 depth적으로 표현하기 입니다.
계층 구조적인 데이터를 가진 테이블에서 계층순서로 데이터를 조회하고, 이를 map에서 depth별로 노출될 수 있는 비지니스 로직을 구현해 보았습니다.
아래의 로직은 다시한번 상기시키기 위해 테스트용으로 작성한것입니다.
# 테이블 데이터 (계층적 구조를 가진 테이블입니다.)
- 테이블 이름 : tree_table
- no = parent_no에따라 (자식 - 부모)관계를 가집니다.
# 1. 최상위 노드들만 순서대로 조회하기 (이는 depth별로 표현할때 반복문의 횟수를 줄이고자 적용했습니다.)
<select id="selectRootTree" parameterType="java.util.HashMap" resultType="java.util.HashMap">
SELECT
pk
, no
, parent_no
, sort
FROM
tree_table
WHERE
parent_no = '*'
</select>
- 조회 결과
# 2. 계층구조의 데이터를 가진 테이블에서 계층순서로 데이터를 조회하기. (중요!!! 이때 순서는 위의 최상위 노들들과 순서가 같아야한다.)
ex, A,a1,a2,B,b1,b2C,c1...순
<select id="selectTree" parameterType="java.util.HashMap" resultType="java.util.HashMap">
WITH RECURSIVE inc AS
(
SELECT
pk
, no
, parent_no
, sort
, CAST(no AS CHAR) lvl
FROM
tree_table
WHERE
parent_no = '*'
UNION ALL
SELECT
tt.pk
, tt.no
, tt.parent_no
, tt.sort
, CONCAT(inc.lvl, "," , tt.no) lvl
FROM
tree_table tt
INNER JOIN
inc
ON tt.parent_no = inc.no
)
SELECT
inc.pk
, inc.no
, inc.parent_no
, inc.sort
FROM
inc
ORDER BY lvl;
</select>
* 주의사항 : lvl의 길이가 길면, 값이 짤려 순서가 이상하게 조회될 수 있다 이럴때는
, CAST(no AS CHAR) lvl ---> , CAST(no AS CHAR(100)) lvl 로 적절히 수정해보자
- 조회 결과
# 3. 비지니스 로직
최상위 노드별로 반복하며, depth를 채우는 방식입니다.
public JhResult tree() {
JhResult result = new JhResult();
HashMap<String, Object> resultData = new HashMap<String, Object>();
HashMap<String, Object> newParam = new HashMap<String, Object>();
List<HashMap<String, Object>> resultList = new ArrayList<HashMap<String, Object>>();
List<HashMap<String, Object>> rootList = new ArrayList<HashMap<String, Object>>();
rootList = testMapper.selectRootTree(newParam);
if(!EmptyUtil.isEmpty(rootList))
{
List<HashMap<String, Object>> treeList = testMapper.selectTree(newParam);
int size = treeList.size();
int idx = 0;
for(HashMap<String, Object> root : rootList) { //최상위 노드별 반복
idx = makeTree(root, treeList, size, idx);
resultList.add(root);
}
}
resultData.put("list", resultList);
result.setResultData(resultData);
result.setResultCode(200);
return result;
}
# 3-1. 계층쿼리로 조회한 리스트를 depth를 가진 map으로 변환하기
재귀를 이용하여 자식을 쌓는 방식입니다. 풀 스캔하지 않도록 인덱스를 활용하여, 조회된 인덱스 이후부터 조회를 하도록 하였습니다.
@SuppressWarnings("unchecked")
private int makeTree(HashMap<String, Object> root, List<HashMap<String, Object>> treeList, int size, int idx) {
List<HashMap<String, Object>> child = null;
if(EmptyUtil.isEmpty(root.get("children")))
{
child = new ArrayList<HashMap<String, Object>>();
root.put("children", child);
}
else{
child = (List<HashMap<String, Object>>)root.get("children");
}
String rootTreeNo = StringUtil.fixNull(root.get("no"),"0");
while(idx < size) {
HashMap<String, Object> tree = (HashMap<String, Object>) treeList.get(idx);
String treeNo = StringUtil.fixNull(tree.get("no"),"0");
String pTreeNo = StringUtil.fixNull(tree.get("parent_no"),"0");
if(rootTreeNo.equals(treeNo)) {
idx++;
continue;
}
else if(rootTreeNo.equals(pTreeNo)) {
child.add(tree);
idx = makeTree(tree, treeList, size, idx);
}
else { //종료조건
break;
}
}
return idx;
}
# 결과
{
"resultCode": 200,
"resultMsg": "",
"resultData": {
"list": [
{
"parent_no": "*",
"no": "A",
"children": [
{
"parent_no": "A",
"no": "a1",
"children": [],
"pk": 2,
"sort": "1"
},
{
"parent_no": "A",
"no": "a2",
"children": [],
"pk": 3,
"sort": "1"
}
],
"pk": 1,
"sort": "1"
},
{
"parent_no": "*",
"no": "B",
"children": [
{
"parent_no": "B",
"no": "b1",
"children": [],
"pk": 5,
"sort": "1"
},
{
"parent_no": "B",
"no": "b2",
"children": [],
"pk": 6,
"sort": "1"
}
],
"pk": 4,
"sort": "1"
},
{
"parent_no": "*",
"no": "C",
"children": [
{
"parent_no": "C",
"no": "c1",
"children": [],
"pk": 8,
"sort": "2"
},
{
"parent_no": "C",
"no": "c2",
"children": [],
"pk": 11,
"sort": "2"
},
{
"parent_no": "C",
"no": "c3",
"children": [],
"pk": 12,
"sort": "2"
}
],
"pk": 7,
"sort": "2"
},
{
"parent_no": "*",
"no": "D",
"children": [
{
"parent_no": "D",
"no": "d1",
"children": [],
"pk": 10,
"sort": "1"
},
{
"parent_no": "D",
"no": "d2",
"children": [],
"pk": 13,
"sort": "1"
}
],
"pk": 9,
"sort": "1"
}
]
}
}
'[Web] > [Spring]' 카테고리의 다른 글
[뉴렉처] Spring MVC 강의 (1,2,3,4,5) (0) | 2022.03.14 |
---|---|
Vo 만드는 법 (0) | 2021.12.21 |
[Spring 분석] 메일 템플릿을 활용한 메일작성 (0) | 2021.10.01 |
context-common.xml 에 대해 알아보자 (0) | 2021.09.15 |
context-*.xml 에 대해 알아보자 (1) (0) | 2021.09.13 |