데이터베이스 삽질기

✒️ 개요

올해 1월쯤부터 DUNPIC.NET의 프론트 엔드 부분을

MDB로 전환해가면서 vscode를 접하고 백엔드 부분도 손보는 작업을 계속하고 있었다.

기존의 코드를 복사 붙여넣기하고 틀린 부분이나, 오류가 나는 부분들을 손보고 어느 정도 완성된 시점에

배포를 시작했는데,

가장 중요한 메뉴인 마법부여 기능에 문제가 있어서 JPA 인터페이스에 작성된 쿼리를 손보면서 많은 삽질을 했었기 때문에

기록해보려고 한다.

💣 헤맸던 점

먼저 내가 원했던 결과를 화면으로 올려보자면

위와 같이 선택한 옵션에 수치가 높은 순서대로 정렬된후,

같은 수치의 카드가 존재 할 경우 옵션의 수가 많은쪽을 위에 표시하는

결과를 뽑아내고 싶었다.

여기서 가장 힘들었던 점은

A와 B카드가 있을때

처음 정렬 즉 수치를 기반으로한 첫 정렬이 수행된 이후

표시되는 옵션이 다른 문제가 있었다.

사진으로 표시해보자면 다음과 같았다.

위와같은 조건일때 선택한 옵션이 아닌 왼쪽카드의 힘+50이 비교되어 정렬되는 문제였다.

이 문제는 테이블 자체가

Card 테이블의 id값으로 판별되는 각각의 항목에 대해 Option 테이블에서 항목마다

효과를 적어주는 방식으로 설계한 구조적인 문제를 간과하여

서브쿼리에서 산출된 id값으로 메인쿼리를 실행할기 때문에 복수의 옵션을 가지고있는 항목의 경우

테이블에 차지하고있는 첫번째 effect의 value가 집계되어 정렬되는 문제였다.

❓ 시도했던 방법들

첫번째 방법으로는

메인 쿼리의 effect컬럼 조건을 고정시키는 방식으로 시도해봤지만,

다수의 옵션을 가지고있는 카드들이 고정된 하나의 effect컬럼만 결과값으로 갖게되기 때문에,

복수의 효과를 가지고있는 카드들을 알수 없게되었다.

두번째 방법으로는 옵션의 상위 선택지인 옵션그룹을 조건절에 넣어보는 것 이었지만,

다른 옵션그룹을 갖는 카드들도 상당수이기 때문에 기각되었다.

세번째 방법으로 서브쿼리의 조건에서 effect 컬럼을 먼저 정렬한뒤 메인쿼리를 실행하는 방법으로 해결했으나

in 으로 접하게되는 메인과 서브쿼리의 부분에서 서브쿼리에서 산출된 순서대로 메인쿼리가 작동하지않는 문제가 발생했다.

구글링과 학부생시절에 공부했던 데이터베이스 책을 뒤져 rownum을 활용해 처리해야한다는 정보를 접했는데,

이해하기가 너무 어려웠다.

이미 배포를 하고있는 시점에서 최대한 문제를 빠르게 해결하고 싶어

이번 문제는 서버단에서 처리하는 방법을 이용했다.

한개의 문장으로 처리되는 기존의 SQL을 서브쿼리와 메인쿼리를 두개의 부분으로 나눠 다음과 같이 처리했다.


        List<Result> subquery = resultDAO.findBySubquery(part, effect);
        List<Result> main = new ArrayList<>();

        for(int i=0; i<subquery.size(); i++){
            int id = subquery.get(i).getId();
            List<Result> fetch = resultDAO.findByIdInJoinTable(id);
            main.addAll(fetch);
        }

서브쿼리의 결과(id)들을 for문을 통해 순서대로 받아와서

findByIdInJoinTable(id)의 매개변수로 활용, 조인테이블에서의 결과를

비어있는 리스트 main에 저장한뒤 return 하는 방법으로 원하는 결과 화면을 만들어 낼 수 있었다.