하나의 상품에 여러 색상과 사이즈가 있다면?
오늘의 주제는 프로젝트를 진행하면서 느낀 점과 해결했던 방법에 대해서 적을 예정이다.
주제는 글의 제목과 같다.
# 어떻게 하면 많은 정보를 한 컬럼에 담을 수 있을까?
우리는 크게 DB에서 테이블을 만들 때 상품 테이블과 상품의 옵션 테이블을 만들게 되는데 상품의 옵션은 다대다 상황이 오기 때문에 상품 테이블에 같이 넣는 것이 아닌 따로 테이블을 만들어주게 됐다.
상품 테이블의 기본키를 옵션 테이블의 외래 키로 사용하면서 각 상품별 색상, 사이즈, 재고, 판매수량을 지정해줄 수 있게 됐다. 여기까지는 순탄하게 흘러갔다. 하지만 우리가 제작해야 할 홈페이지의 주제는 쇼핑몰이었고 한 상품에 다양한 색상과 사이즈가 존재하다는 것을 알게 되기까지는 얼마 걸리지 않았다.
특히, 내가 리액트를 잘 만지지 못하는 문제가 한몫했다.
- 판매자가 올릴 수 있는 색상을 지정해줘야할까?
가장 처음 막힌 부분의 의문이었다. 사실 사용자가 어떤 색상을 넣든 간에 상관없이 모든 색상을 수용하는 DB를 만들고 싶었다. 하지만 그건 쉽지 않았고 포기하려고 했다.
가장 처음 했던 것은 판매자가 BLACK, YELLOW, GREEN 등 값을 입력하게되면 DECODE를 통해서 해당 값이 있는지 없는지 그리고 있다면 해당 값을 해당 값의 이름을 가진 컬럼에 넣을 수 있었다. 그러나 각 상품마다 들어갔던 색상은 달랐고 여러가지 상품을 한 번에 출력할 때는 곳곳에 null값이 들어가있는 상황을 마주하게 됐다.
내가 리액트를 잘했더라면 null값을 걸러내서 <div style={{backgroundColor : product_color}}>로 바로 적용시킬 수 있었겠지만 아쉽게 리액트를 잘 하지 못했던 나는 차선택의 방법을 생각해냈다.
- 그럼 DB에서 출력할 때 null값이 없이 완벽하게 출력할 수 있을까?
다음 질문을 실행하기 위해서 여러 방법을 거쳤고 그 방법 중에 차라리 color테이블을 만들어서 color 컬럼을 color1부터 color 12까지 만들면 되지 않을까였다. 실험은 성공했다. product 테이블과 color테이블을 조인하고나니 react에서 사용하는 map을 통해서 한 번에 빈칸 없이 출력할 수 있었다.
하지만.... 쿼리 출력을 받는 VO가 상당히 지저분해졌다.
ex) String color1, String color2....
테이블의 컬럼도 많을 뿐만 아니라 vo까지 지저분해져서 나중에 조회속도에 차질이 생길 것 같아 새로운 방법을 생각해내야 했다.
- 해답은 언제나 가까이 있다. SPLIT
여러 방법을 거치고 나서 위에 있는 사진과 같은 테이블이 만들어졌다.
하나의 상품에 여러가지의 색상을 담을 수 있고 해당 색상에는 또 여러가지 사이즈를 담아낼 수 있다.
[ 최종 쿼리문 ]
select * from
(select ROW_NUMBER() OVER(ORDER BY p.product_seq) RNUM, p.* ,c.product_color, c.product_size as product_size2 from product p,
(select product_seq, substr(xmlagg(xmlelement(col,',',product_color)).extract('//text()').getstringval(),2)product_color, substr(xmlagg(xmlelement(col,',',product_size)).extract('//text()').getstringval(),2)product_size from optiontest group by product_seq) c
where p.product_seq = c.product_seq) where rnum between ((1-1)*10)+1 and (1*10) and product_category = '치마' and product_color like '%yellow%' and product_size2 like '%95%';
생각보다 쿼리문이 길긴 하지만 원하는 페이지의 번호에 상품이 10개씩 출력되고, 상품 카테고리도 선택할 수 있으며 상품의 색상, 사이즈까지 선택할 수 있는 쿼리문이다.
쿼리문을 실행하고 나서 List형태의 vo를 받아올 수 있게 되는데 VO를 한번 살펴보자
[ ProductVO ]
package com.example.demo.vo;
import lombok.Data;
@Data
public class ProductColorLastVO {
int product_seq;
String product_title;
int product_price;
String product_img;
String product_gender;
int product_stock;
int product_saled;
String product_category;
String product_content;
String product_color;
String product_size;
int product_pageNum;
String[] colors;
String[] sizes;
String select_color;
String select_size;
public void setProduct_color(String product_color) {
colors=product_color.split(",");
}
public void setProduct_size(String product_size) {
sizes=product_size.split(",");
}
}
쿼리문을 출력하게 되면 아래와 같은 결과값이 나오게 되는데 product_color를 보면 여러 색이 한 컬럼에 들어가있다.
해당 컬럼의 값을 String에 모두 넣고 color[]배열을 만들어서 색상 전체를 받아온 값에서 split을 사용해서 , 구분자로 값을 나눌 수 있게 됐다.
이 문제를 해결하기 위해서 4일정도 밤낮없이 계속 코드생각만 했었는데 많은 발전이 있었던 것 같다.
몰랐던 decode나 여기에서 언급하지 않은 많은 방법들을 직접 해보면서 이게 왜 되는지 그리고 어떤 부분에서 고민하면서 테이블을 짜고 리스트를 출력할 때 어떤 join을 사용해야 하는지 고민할 수 있었던 시간이었다.
현재 쿼리문에서는 substr를 사용했지만 쿼리문을 줄일 수 있으면서도 같은 결과물을 낼 수 있는 다른 방법이 있다고 해서 그것을 시도해볼 예정이다.
많은 것을 하지는 못했지만 적어도 내가 했던 것은 제대로 알고가는 시간이 될 수 있어서 좋다. 천천히 그리고 꾸준히 해결하는게 좋다.