1. 트리 구조 데이터 조회시 문제점
화면 개발을 하면서 장비 목록을 트리 구조로 보여줘야하는 부분이 있었다. 리프노드인 장비 아이템이 모두 존재하는 경우에는 문제가 되지 않았지만 검색 결과로 한 카테고리에 장비 아이템이 없는 경우에 문제가 발생했다.
장비 아이템이 없는데 '가스설비 - 측정설비 - 계량기' 카테고리 메뉴가 노출되는 것이었다. 이것은 문제였다. 사용자에게 보여주어야하는 화면은 아래와 같았기 때문이다.
그래서 이 부분을 SQL과 Java Stream을 사용하여 문제를 해결해보려고 한다.
2. SQL로 메뉴 데이터 조회
데이터베이스는 MariaDB 10.4.27 버전을 사용했다. 먼저 테스트에 사용할 테이블을 만들어준다.
-- 최상위 구분 Part 테이블
CREATE TABLE `part` (
`no` int(11) NOT NULL AUTO_INCREMENT,
`part_cd` varchar(45) DEFAULT NULL,
`part_nm` varchar(45) DEFAULT NULL,
PRIMARY KEY (`no`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- 중간 메뉴 Eqpt Menu 테이블
CREATE TABLE `eqpt_menu` (
`no` int(11) NOT NULL AUTO_INCREMENT,
`part_cd` varchar(45) DEFAULT NULL,
`menu_cd` varchar(45) DEFAULT NULL,
`prnt_menu_cd` varchar(45) DEFAULT NULL,
`menu_nm` varchar(45) DEFAULT NULL,
PRIMARY KEY (`no`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
-- 끝단 장비 아이템 Eqpt 테이블
CREATE TABLE `eqpt` (
`no` int(11) NOT NULL AUTO_INCREMENT,
`part_cd` varchar(45) DEFAULT NULL,
`eqpt_menu_menu_cd` varchar(45) DEFAULT NULL,
`eqpt_menu_prnt_menu_cd` varchar(45) DEFAULT NULL,
`eqpt_nm` varchar(45) DEFAULT NULL,
`loc` varchar(45) DEFAULT NULL,
PRIMARY KEY (`no`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
테이블을 생성한 후에 데이터를 추가해준다.
-- part 테이블
insert into part (part_cd, part_nm) values ('01', '기계');
-- eqpt_menu 테이블
insert into eqpt_menu(part_cd, menu_cd, prnt_menu_cd, menu_nm) values ('01', 'eq01', 'eq', '기계설비');
insert into eqpt_menu(part_cd, menu_cd, prnt_menu_cd, menu_nm) values ('01', 'eq0101', 'eq01', '냉방설비');
insert into eqpt_menu(part_cd, menu_cd, prnt_menu_cd, menu_nm) values ('01', 'eq010101', 'eq0101', '실외기');
insert into eqpt_menu(part_cd, menu_cd, prnt_menu_cd, menu_nm) values ('01', 'eq02', 'eq', '가스설비');
insert into eqpt_menu(part_cd, menu_cd, prnt_menu_cd, menu_nm) values ('01', 'eq0201', 'eq02', '측정설비');
insert into eqpt_menu(part_cd, menu_cd, prnt_menu_cd, menu_nm) values ('01', 'eq020101', 'eq0201', '계량기');
-- eqpt 테이블
insert into eqpt(part_cd, eqpt_menu_menu_cd, eqpt_menu_prnt_menu_cd, eqpt_nm, loc) values('01', 'eq01010101', 'ep010101', '실외기1', 'A동 문화관 3층 옥상');
insert into eqpt(part_cd, eqpt_menu_menu_cd, eqpt_menu_prnt_menu_cd, eqpt_nm, loc) values('01', 'eq01010102', 'ep010101', '실외기1', 'A동 문화관 3층 옥상');
insert into eqpt(part_cd, eqpt_menu_menu_cd, eqpt_menu_prnt_menu_cd, eqpt_nm, loc) values('01', 'eq01010103', 'ep010101', '실외기1', 'A동 문화관 3층 옥상');
insert into eqpt(part_cd, eqpt_menu_menu_cd, eqpt_menu_prnt_menu_cd, eqpt_nm, loc) values('01', 'eq01010104', 'ep010101', '실외기4', 'C동 식당 지하 문 옆');
insert into eqpt(part_cd, eqpt_menu_menu_cd, eqpt_menu_prnt_menu_cd, eqpt_nm, loc) values('01', 'eq01010105', 'ep010101', '실외기5', 'C동 식당 지하 문 옆');
insert into eqpt(part_cd, eqpt_menu_menu_cd, eqpt_menu_prnt_menu_cd, eqpt_nm, loc) values('01', 'eq01010106', 'ep010101', '실외기6', 'C동 식당 지하 문 옆');
insert into eqpt(part_cd, eqpt_menu_menu_cd, eqpt_menu_prnt_menu_cd, eqpt_nm, loc) values('01', 'eq01010107', 'ep010101', '실외기7', 'C동 식당 지하 문 옆');
insert into eqpt(part_cd, eqpt_menu_menu_cd, eqpt_menu_prnt_menu_cd, eqpt_nm, loc) values('01', 'eq01010108', 'ep010101', '실외기8', 'D동 지상주차장 입구');
insert into eqpt(part_cd, eqpt_menu_menu_cd, eqpt_menu_prnt_menu_cd, eqpt_nm, loc) values('01', 'eq01010109', 'ep010101', '실외기9', 'D동 지상주차장 입구');
insert into eqpt(part_cd, eqpt_menu_menu_cd, eqpt_menu_prnt_menu_cd, eqpt_nm, loc) values('01', 'eq01010110', 'ep010101', '실외기10', 'D동 지상주차장 입구');
insert into eqpt(part_cd, eqpt_menu_menu_cd, eqpt_menu_prnt_menu_cd, eqpt_nm, loc) values('01', 'eq02010101', 'ep020101', '계량기1', 'B동 대강당 7층 화장실 앞');
insert into eqpt(part_cd, eqpt_menu_menu_cd, eqpt_menu_prnt_menu_cd, eqpt_nm, loc) values('01', 'eq02010102', 'ep020101', '계량기1', 'B동 대강당 7층 화장실 앞');
데이터가 잘 추가되었는지 조회를 통해 확인해보자.
데이터 추가가 완료되었으니 트리구조 데이터를 뽑아보자. 장비 테이블의 loc(장비 설치 위치)컬럼에 '문화관'이 포함된 장비 목록을 조회한다.
SELECT
part_cd AS PART_CD,
part_nm AS MENU_NM,
'' AS MENU_CD,
'' AS PRNT_MENU_CD,
'0' AS LEVEL,
'N' AS LEAF_YN
FROM
part
UNION ALL
SELECT
em.PART_CD,
em.MENU_NM,
em.MENU_CD,
em.PRNT_MENU_CD,
em.LEVEL,
CASE
WHEN e.leaf_yn IS NULL THEN 'N'
ELSE leaf_yn
END AS LEAF_YN
FROM
eqpt_menu em
LEFT OUTER JOIN
(SELECT
*,
'Y' AS LEAF_YN
FROM
eqpt
WHERE
eqpt.loc LIKE '%문화관%') e ON em.menu_cd = e.eqpt_menu_prnt_menu_cd
GROUP BY em.MENU_NM;
쿼리를 실행하면 아래와 같은 데이터를 뽑을 수 있다.
그런데 여기서 문제가 드러난다. 마지막 세 줄을 보면 '가스설비', '측정설비', '계량기' 가 조회된 것을 알 수 있다. 가스설비 카테고리는 끝단 장비 아이템이 없기 때문에 조회 결과에서 제외되어야하는데 포함되어버린 것이다. (쿼리로 제외할 수 있는 방법 아시는 분 계시다면 댓글 부탁드립니다 😭) 그래서 장비아이템이 없는 중간 장비 메뉴를 삭제시키는 작업을 Java Stream 에서 처리해주려고 한다.
3. 하위 장비 목록 조회
원래 계획은 SpringBoot를 DB에 연결하고 데이터를 조회해서 Java Stream으로 데이터처리하는 부분을 구현하려고 하였다. 하지만 DB데이터를 조회하는 것보다 Java 프로젝트에 더미 데이터를 만들고 테스트를 진행하는 것이 더 좋을 것 같아서 후자의 방향으로 개발하도록 하겠다.
4. Java Stream 으로 Tree 구조 데이터 만들기
ㄹ호
'Java' 카테고리의 다른 글
한글 Levenshtein Distance 구현 (0) | 2024.12.08 |
---|---|
한글 초성, 중성, 종성 분리하기 (0) | 2024.12.08 |
[Java] Stream 문제 풀어보기 (0) | 2024.06.05 |