SQL 활용도 향상 방법

  • SELECT문은 단지 우너하는 데이터를 읽어달라는 문장이 아니라 데이터를 읽어
    필요한 가공처리를 한 후 그 결과를 요구하는 문장이다. 우리가 어느 선까지 가공 처리된
    SELECT 문장을 생성할 수 있으냐에 따라 SQL의 역할은 크게 달라진다.

3.1 DECODE함수를 이용한 IF처리

  • DECODE함수는 오로지 '='로만 비교되어야 하며, 함수를 수행한 결과는 항상
    하나의 값만 가질 수 있다.
  • 부등호 비교를 해결해야 할 경우는 SIGN, FLOOR, CEIL함수를 사용해야 한다.
  • 오라클 8i 부터는 CASE가 지원되므로 DECODE보다는 CASE사용이 더 유리하다.

  • 문자열의 부등호 비교를 위한 처리는 GREATEST, LEAST 함수를 사용하여 해결할 수 있다.
  • GREATEST, LEAST의 장점은 비교되는 값들의 데이터 타입에 전혀 영향을 받지 않으며,
    SIGN, FLOOR, CEIL와 달리 연산을 하지 않아도 되어 부하가 적다.

h2.SUM(DECODE...)의 활용

  • DECODE를 가장 빛나게 해주는 활용방법은 SUM함수와 함께 사용하는 경우이며,
    이는 우리가 SQL로 읽어둔 데이터를 수많은 절차형 언어로 다시 가공해야 하는 번거로움을 현격히
    줄여준다.

3.2.1 SUM(DECODE)의 원리

3.2.2 SUM(DECODE...)의 확장

가 전체 집합의 확장

  • SQL 처리의 기본이 되는 전체 집합은 테이블이나 뷰, 인라인뷰가 된다.
  • 그렇다면 이 전체 집합을 늘리는 방법은 조인을 사용함으로써 해결된다.
  • 정보의 가공에 필요한 정보와 추가적인 처리영역을 필요로 한다면 조인을 통해 SQL내로 끌어들일 수 있다.

대분류의 확장

  • 확장한 전체집합에서 WHERE 절에서 선별한 처리할 영역을 표시한 것

중분류의 확장

  • 전체 집합에 모여진 ROW들에 대해서 선별된 작업 영역의 모든 데이터들은 다양한 형태의
    단위 집합으로 모여야 한다. 이것을 중분류라고 한다.
  • 중분류는 작업영역인 대분류 내의 대상 ROW들 중에서 'GROUP BY'를 사용하여 분류하여,
    필요한 따라 'HAVING'을 사용하여 다시 선별할 수 있다.

로우단위의 확장

  • 로우들을 가공 처리하는 방법 예시
  • 매출 테이블에서 매출일자가 98년 07월인 데이터를 읽어서 각 부서별로 '당일 매출수량',
    '현재일부터 1주일간의 매출수량','월간합계','각 부서별로 가장 마지막에 발생한 일자의 매출수량'을
    구하는 문장이다.

3.2.3 SUM(DECODE...)사용시 주의사항

NULL값의 처리

  • NULL값은 어떤 값보다 크지도 작지도 않으며 NULL값과의 연산 결과는 무조건 NULL값이 된다.
  • 조건에서 어떤 컬럼을 비교했을 때, NULL값이 있는 경우는 아예 처리 대상에서 제외된다.
  • 이런 이유로 NVL함수를 사용하여 NULL값을 없애는 방법을 많이 사용하나 이는 불필요한 연산을 증가시킬 수 있다.

잘못된 사용 예올바른 사용 예
SELECT SUM(DECODE(NVL(col1, 0), 1, NVL(col2, 0))), ...SELECT SUM(DECODE(col1, NULL, NVL(col2, 0))), ...
SELECT SUM(DECODE(col1, 1, NVL(col2, 0) + NVL(col3, 0))), ...SELECT NVL(SUM(DECODE(col1, 1, col2)), 0) + NVL(SUM(DECODE(col1, 1, col3)), 0) ...
SELECT SUM(DECODE(col1, 1, col2, 0), ...SELECT SUM(DECODE(col1, 1, col2)), ...

반복 DECODE의 감소

  • SUM(DECODE...)용법에서 가장 오버헤드를 주는 부분은 DECODE문을 연속해서 사용하는 경우이다.
사례1) 제조업을 하고 있는 (주)청산은 자재수급이 원활하지 않아 생산에 많은 차질을 빚고 있었다.
그 원인을 분석하기 위해 우선 다음 그림과 같이 거래선별로 발주에서 입고까지 소요되는 구매 리드타임을 다양한 범위별로 집계해보고자 한다. 구매 리드 타임은 발주일에서 입고일 사이의 기간을 말하며
아직 입고가 되지 않은 건은 오늘까지의 기간을 적용한다. 설명을 간단하게 하기 위하여 여기서
사용되는 일자들은 date 타입으로 정의되어 있으며 일자에 '시분초'는 입력되지 않았다고 가정한다.

SUM(DECODE...)와 GROUP BY 비교

  • 위쪽 SQL에서 발생한 비효율을 찾아보면,
    첫째, WHERE 조건을 만족한 모든 로우들에 대해 DECODE처리와 환율 계산을 위한 연산이 반복적으로
    수행된 것이다. 내용상으로 볼 때 이러한 처리는 단기, 장기 구분이나 연도별로 데이터가 집계된 후에
    처리해도 무방하다.
    둘째, 국가와 환율 테이블은 국가와 가입년도로 집계된 후에 조인해도 관계가 없으므로
    로우수가 많은 보험 가입실적 테이블에서 조인할 필요가 없다는 것이다.
  • 아래의 경우 중간 집합을 먼저 생성한 후 나머지 조인과 DECODE처리를 하였다.
  • 실질적으로 SELECT-LIST의 DECODE는 실제로 줄어든 것이 없는 것처럼 보이지만
    DECODE를 처리할 대상 집합이 많이 줄었들었으므로 수행횟수가 줄어들 수 있다.

h4.COUNT(DECODE...)의 활용

SQL을 어떻게 공부할 것인가?

  • 어려운 문제를 많이 풀어보라
  • 원리와 기본에 충실하라
  • 항상 SQL의 실행 계획에 염두에 두라