Darren's Devlog

[불친절한SQL] 기초쿼리, WHERE절 - 3 본문

SQL

[불친절한SQL] 기초쿼리, WHERE절 - 3

Darren Gwon 2022. 12. 6. 13:11
반응형

○ 활용 예제

열 가공

WHERE 절의 열을 가공하면 쿼리의 성능이 저하될 수 있다.

가급적 열을 가공하지 않는 편이 바람직하다.

 

아래 쿼리는 연봉이 36000 이상인 행을 조회한다.

좌측 쿼리는 산술 연산이 행의 개수만큼 수행된다.

우측 쿼리는 산술 연산을 수행한 결과로 조건을 평가할 수 있다.

SELECT *
   FROM emp
WHERE sal * 12 >= 36000;
SELECT *
   FROM emp
WHERE sal >= 36000 / 12;

 

아래 쿼리는 deptno가 10이고 job이 CLERK인 행을 조회한다.

좌측 쿼리는 결합 연산자로 열을 가공했다.

우측 쿼리처럼 AND 조건을 사용해야 한다.

SELECT * 
   FROM emp 
WHERE deptno || job = '10CLERK';
SELECT *
   FROM emp
WHERE deptno = 10
      AND job = 'CLERK';

 

아래 쿼리는 ename이 A로 시작하는 행을 조회한다.

좌측 쿼리는 SUBSTR 함수를 사용했다.

우측 쿼리처럼 LIKE조건을 사용하는 편이 바람직하다.

SELECT *
   FROM emp
WHERE SUBSTR(ename, 1, 1) = 'A';
SELECT *
   FROM emp
WHERE ename LIKE 'A%';

 

아래 쿼리는 ename에 ON이 포함된 행을 조회한다.

좌측 쿼리는 INSTR 함수를 사용했고,

우측 쿼리는 LIKE조건을 사용했다.

LIKE 조건의 패턴 양측에 특수문자(%, _)를 사용한 경우

LIKE 조건보다 INSTR 함수를 사용하는 편이 성능 측명에서 유리할 수 있다.

SELECT *
   FROM emp
WHERE INSTR(ename, 'ON') > 0;
SELECT *
   FROM emp
WHERE ename LIKE '%ON%';

 

아래 쿼리는 1987-04-19에 입사한 사원을 조회한다.

좌측 쿼리는 hiredate에 TO_CHAR함수를 사용했다.

우측 쿼리로 변경할 수 있지만 hiredate에 시간이 포함되어 있다면 쿼리의 결과가 달라진다.

SELECT *
   FROM emp
WHERE TO_CHAR(hiredate, 'YYYYMMDD')
           = '19870419';
SELECT *
   FROM emp
WHERE hiredate = DATE '1987-04-19';

 

DATE 타입으로 조회할 시 아래와 같이 작성해야 동일한 결과를 보장할 수 있다.

SELECT *
  FROM emp
 WHERE hiredate >= DATE '1987-04-19'
   AND hiredate <  DATE '1987-04-19' + 1;

 

아래 쿼리는 WHERE절에 CASE 표현식을 사용했다.

deptno가 10인 경우 empno가 7839인 행,

deptno가 10이 아닌 경우 mgr이 7839인 행을 조회한다.

SELECT empno, ename, mgr, deptno
  FROM emp
 WHERE CASE deptno WHEN 10 THEN empno ELSE mgr END = 7839;

 

위 쿼리처럼 CASE 표현식에 다수의 열을 사용하는 경우 쿼리의 성능이 저하될 수 있다.

아래와 같이 OR 조건을 사용하는 편이 바람직하다.

SELECT empno, ename, mgr, deptno
  FROM emp
 WHERE ((deptno = 10 AND empno = 7839) OR (deptno <> 10 AND mgr = 7839));

 

deptno 열이 NULL을 허용하면 아래와 같이 작성해야한다.

SELECT empno, ename, mgr, deptno
  FROM emp
 WHERE ((deptno = 10 AND empno = 7839) OR (LNNVL (deptno = 10) AND mgr = 7839));

 

동적 조건

바인드 변수의 인수에 다라 조건이 변경되는 것을 동적 조건이라고 한다.

 

아래 쿼리는 WHERE 절에 바인드 변수를 사용한 쿼리다.

좌측 쿼리는 deptno가 10, 우측 쿼리는 deptno가 20인 행을 반환한다.

VAR v1 NUMBER = 10;

SELECT ename, deptno
  FROM emp
 WHERE deptno = :v1;
EXEC :v1 := 20;

SELECT ename, deptno
  FROM emp
 WHERE deptno = :v1;

 

날짜 기간 조회

날짜 값은 다양한 데이터 타입에 저장될 수 있다.

날자 값을 저장하는 데이터 타입은 데이터 모델링 분야의 오랜 논쟁거리 중 하나다.

DATE 타입이나 TIMESTAMP 타입을 사용하는 편이 바람직하다.

데이터 타입
VARCHAR2(8) YYYYMMDD 형식의 시분초가 포함되지 않은 문자 값
VARCHAR2(14) YYYYMMDDHH24MISS 형식의 시분초가 포함된 문자 값
DATE 시분초가 포함된 DATE 값
TIMESTAMP 소수점 이하 초가 포함된 TIMESTAMP 값

아래는 2050년부터 2051년까지의 기간을 조회하는 쿼리다.

SELECT *
  FROM t1
 WHERE c1 >= TO_DATE(  '205001', 'YYYYMM'  )
   AND c1 <  TO_DATE('20511231', 'YYYYMMDD') + 1;

 

아래 쿼리는 '2051-12-31 00:00:01' 과 '2051-12-31 00:00:00' 1초 차이로

false에 해당하여 3행만 조회된다.

SELECT *
  FROM t1
 WHERE c1 >= TO_DATE('205001'  , 'YYYYMM'  )
   AND c1 <= TO_DATE('20511231', 'YYYYMMDD');

 

아래는 2050년 1월부터 2050년 2월까지의 기간을 조회하는 쿼리다.

LAST_DAY(TO_DATE('205002', 'YYYYMM'))로 반환된 2050-02-28 00:00:00에 하루를 더하여

c1 < DATE '2050-03-01 00:00:00' 조건으로 조회된다.

 

아래는 2050년 1월 1일부터 2050년 1월 2일가지의 기간을 조회하는 쿼리다.

SELECT *
  FROM t1
 WHERE c1 >= TO_DATE('20500101', 'YYYYMMDD')
   AND c1 <  TO_DATE('20500102', 'YYYYMMDD') + 1;

 

아래 쿼리처럼 BETWEEN 조건을 사용하면 c1이 2050-01-02 00:00:01인 행이 누락된다.

TO_DATE('20500102', 'YYYYMMDD') 표현식이 2050-01-02 00:00:00으로 변환되기 때문이다.

  SELECT *
    FROM t1
   WHERE c1
 BETWEEN TO_DATE('20500101', 'YYYYMMDD')
     AND TO_DATE('20500102', 'YYYYMMDD');

반응형
Comments