백엔드DB / SQL
3

MySQL 계층형 메뉴 구조 설계 및 조회하기

MySQL 계층형 메뉴 구조 설계 및 조회하기

프로젝트를 진행하면서 관리자 메뉴를 계층형으로 관리해야 하는 상황이 생겼습니다.

예를 들어:

서비스관리
 ├─ 사용자관리
 │   ├─ 사용자조회
 │   └─ 사용자등록
 └─ 게시판관리
     └─ 게시글관리

이런 형태의 메뉴 구조입니다.

추가로 권한 그룹별로 접근 가능한 메뉴를 관리해야 했기 때문에 아래와 같은 구조로 설계했습니다.


테이블 구조

1. 메뉴 기본 테이블

메뉴 자체를 관리하는 테이블입니다.

CREATE TABLE MENU_BSC (
    MENU_ID     VARCHAR(20)  NOT NULL,
    USER_TYPE   CHAR(1)      NOT NULL,
    MENU_NAME   VARCHAR(30)  NOT NULL,
    MENU_LEVEL  CHAR(1)      NOT NULL,
    PARENT_MENU_ID VARCHAR(20),
    MENU_ORDER  INT,
    MENU_DESC   VARCHAR(200),
    PROGRAM_ID  VARCHAR(20),
    USE_YN      CHAR(1) DEFAULT 'Y',
    PRIMARY KEY (MENU_ID)
);

주요 컬럼 설명

컬럼명설명
MENU_ID메뉴 고유 ID
MENU_LEVEL메뉴 레벨 (1~3)
PARENT_MENU_ID부모 메뉴 ID
MENU_ORDER메뉴 정렬 순서

핵심은 PARENT_MENU_ID 입니다.

부모 메뉴를 참조하면서 계층 구조를 만들 수 있습니다.


메뉴 데이터 예시

INSERT INTO MENU_BSC
(MENU_ID, USER_TYPE, MENU_NAME, MENU_LEVEL, PARENT_MENU_ID, MENU_ORDER)
VALUES
('M100', 'A', '서비스관리', '1', NULL, 1),
('M110', 'A', '사용자관리', '2', 'M100', 1),
('M111', 'A', '사용자조회', '3', 'M110', 1);

데이터 구조는 이렇게 연결됩니다.

M100 서비스관리
 └─ M110 사용자관리
     └─ M111 사용자조회

권한 메뉴 매핑 테이블

권한 그룹별 메뉴 접근 여부를 관리하는 테이블입니다.

CREATE TABLE AUTH_MENU_MPP (
    AUTH_GROUP_CODE CHAR(5) NOT NULL,
    MENU_ID         VARCHAR(20) NOT NULL,
    AUTH_YN         CHAR(1) DEFAULT 'N',
    USE_YN          CHAR(1) DEFAULT 'Y',
    PRIMARY KEY (AUTH_GROUP_CODE, MENU_ID)
);

계층형 조회 쿼리

이제 실제로 계층형 데이터를 조회해봅니다.

SELECT
    M1.USER_TYPE        AS 사용자구분,
    AM.AUTH_GROUP_CODE  AS 권한그룹코드,

    M1.MENU_ID          AS 메뉴1_ID,
    M1.MENU_NAME        AS 메뉴1명,

    M2.MENU_ID          AS 메뉴2_ID,
    M2.MENU_NAME        AS 메뉴2명,

    M3.MENU_ID          AS 메뉴3_ID,
    M3.MENU_NAME        AS 메뉴3명,

    AM.AUTH_YN          AS 권한여부

FROM MENU_BSC M1

LEFT JOIN MENU_BSC M2
    ON M2.PARENT_MENU_ID = M1.MENU_ID
   AND M2.MENU_LEVEL = '2'

LEFT JOIN MENU_BSC M3
    ON M3.PARENT_MENU_ID = M2.MENU_ID
   AND M3.MENU_LEVEL = '3'

LEFT JOIN AUTH_MENU_MPP AM
    ON AM.MENU_ID = M3.MENU_ID

WHERE M1.MENU_LEVEL = '1'

ORDER BY
    M1.MENU_ORDER,
    M2.MENU_ORDER,
    M3.MENU_ORDER;

왜 같은 테이블을 여러 번 JOIN 하는가?

처음에는 이해가 잘 안됐는데 핵심은 이것이었습니다.

MENU_BSC M1
MENU_BSC M2
MENU_BSC M3

같은 메뉴 테이블을:

  • M1 = 1뎁스
  • M2 = 2뎁스
  • M3 = 3뎁스

역할로 나눠서 조회하는 것입니다.


JOIN 흐름 이해하기

1단계

FROM MENU_BSC M1
WHERE M1.MENU_LEVEL = '1'

1뎁스 메뉴만 조회합니다.


2단계

LEFT JOIN MENU_BSC M2
    ON M2.PARENT_MENU_ID = M1.MENU_ID

2뎁스 메뉴의 부모가 1뎁스 메뉴인 데이터를 찾습니다.

즉:

2뎁스 부모ID = 1뎁스 메뉴ID

3단계

LEFT JOIN MENU_BSC M3
    ON M3.PARENT_MENU_ID = M2.MENU_ID

3뎁스 메뉴의 부모가 2뎁스 메뉴인 데이터를 찾습니다.

즉:

3뎁스 부모ID = 2뎁스 메뉴ID

최종 결과 예시

사용자구분권한그룹코드메뉴1명메뉴2명메뉴3명권한여부
AG0001서비스관리사용자관리사용자조회Y
AG0001서비스관리사용자관리사용자등록Y
AG0001서비스관리게시판관리게시글관리Y

정리

이번 작업을 하면서 느낀 핵심은:

  • 계층형 메뉴는 결국 자기 자신을 JOIN 하는 구조
  • PARENT_MENU_ID 가 부모-자식 관계를 만든다
  • 같은 테이블을 여러 역할(M1, M2, M3)로 나눠 조회한다
  • 권한 테이블을 추가하면 권한별 메뉴 제어가 가능하다

실무에서 관리자 시스템이나 ERP, 그룹웨어 등에서 자주 사용하는 구조라는 것도 알게 되었습니다.

댓글

(0)
MySQL 계층형 메뉴 구조 설계 및 조회하기 | 강민석의 개발블로그