MySQL에서의 CASE문(like switch-case) 사용하기


SELECT CASE deliterm

             WHEN '1' THEN '1~3일'

             WHEN '2' THEN '3~5일'

             WHEN '3' THEN '5~7일'

             WHEN '4' THEN '7~10일'

             WHEN '5' THEN '10일 이상'

             ELSE '-'

             END AS delitermstr


             CASE deliexp

             WHEN '0' THEN '착불'

             WHEN '-1' THEN '판매자부담'

             ELSE CONCAT('구매자 부담(', deliexp, '원)')

             END AS deliexpstr

   FROM sGoods;



위의 예제에서 deliterm과 deliexp는 각각 ENUM, SMALL INT형의 자료이며

deliterm은 1, 2, 3, 4, 5로 각각 배송 기간을 구분하여 저장하고 있으며,

deliexp는 0, -1, (양의 정수)로 각각 0은 착불, -1은 판매자 부담

그리고 양의 정수일 경우 구매자가 부담할 배송료의 액수를 나타낸다.



MySQL의 CASE문은 두 가지의 용법이 있는데,

그 용법은 다음과 같다.


1. CASE value WHEN compare-value THEN result [WHEN [compare-value] THEN [result] ... ] [ELSE result] END


이것은 value == compare-value일 때 result를 반환한다.



2. CASE WHEN [condition] THEN result [WHEN [condition] THEN result ...] [ELSE result] END


이것은 condition == true일 때 result를 반환한다.





그리고 1, 2 모두 앞의 compare-value 혹은 condition을 만족하지 않으면 ELSE의 값을 돌려주게 되며,

ELSE문을 생략하였을 경우에는 NULL이 반환된다.


그리고, 반환값은 INTEGER, DOUBLE, STRING 셋 중 하나가 되며,

type은 THEN 절 이후에 주어진 result의 type에 의해 결정된다.


참고 사이트(MySQL 메뉴얼);

http://www.mysql.com/doc/en/Control_flow_functions.html




------------------------------------------------------------------------------------------------





'①'와 같은 원문자들을 그냥 일반 숫자로 가져오려고 case문을 사용했다.


SELECT
  CASE race_no
  WHEN '①' THEN '1'
  WHEN '②' THEN '2'
  ELSE race_no
  END
FROM tbl

그런데, 제대로 못 갖고 오더라.. 인코딩의 차이인가...ㅋ

그래서 이렇게 했더니 됐다..

SELECT
  CASE CONVERT( race_no USING UTF8 )
  WHEN CONVERT( '①' USING UTF8 ) THEN '1'
  WHEN CONVERT( '②' USING UTF8 ) THEN '2'
  ELSE race_no
  END
FROM tbl






이번에 INSERT쿼리를 개선하다가 추가적으로 개선한 사항이 있어 메모해둔다.

 

1. 다량의 INSERT

한 테이블에서 다량의 데이터를 SELECT해서,

조건을 검사한 후에 다시 INSERT를 해야 하는 상황이 있었다.

우선 조건에 맞는 데이터를 SELECT 한 후에, 페이지에서 조건별로 type을 분기 하고,

다시 다량의 INSERT를 해야 했다.

 

rows수가 많아짐에 따라 페이지에서 연결이 끊어지는 현상이 발생하였다.

 

이를 개선하기 위해

INSERT
    INTO DB1.table1
        SELECT
            'type1', [나머지 insert parameters (열의 순서를 정확히 맞춰줘야 함. 없이면 null으로 라도 채워넣어야 함)]

        FROM DB1.table2
        WHERE column1 = [조건1] AND column2 IN ([조건2]) AND column3 > [조건3]

    UNION

        SELECT

            'type2', [insert parameters]

        FROM DB1.table2
        WHERE column1 <> [조건1] AND column2 NOT IN ([조건2]) AND column3 > [조건3]

 

이렇게 쿼리를 개선하였으나,

type1과 type의 조건1,2가 정확히 상호배타적이고, 그 합이 조건3에 의해 설정된 범위의 전체 집합이 되므로,

이는 CASE문을 이용하면 개선할 수 있었다.

 

INSERT
    INTO DB1.table1
        SELECT
             CASE WHEN column1 = [조건1]

                      AND column2 IN ([조건2])

             THEN 'type1'

             ELSE 'type2'

             END, [나머지 insert parameters]

        FROM DB1.table2
        WHERE column3 > [조건3]

 

결과적으로 derive수가 2번에서 1번으로 줄어든 셈이다.

인덱스가 걸려있어서 첫번째 쿼리도 크게 지장은 없겠지만,

쓸데없이 일을 2번할 필요는 없는 것이다. (성능 향상)