본문 바로가기
DataBase/Oracle

DQL) WHERE 구문 (동등비교, between a and b, like/not like, is null/is not null, in/not in, and, or, not, 연산자 우선 순위)

by 박채니 2022. 4. 14.

안녕하세요, 코린이의 코딩 학습기 채니 입니다.

 

개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.


WHERE 구문

- 지정한 테이블에서 행을 추려내기 위한 조건절

- 각 행마다 컬럼 값을 검사해서 true가 반환된 행은 결과 집합 포함, false가 반환된 행은 결과 집합에서 제외

※ null 값도 false처리 되므로 null 값들도 false → 결과 집합 포함 안됨

연산자 설명
= 같다
!=, <>, ^= 같지 않다
>, >=, <, <= 크다, 크거나 같다, 작다, 작거나 같다
between a and b a 이상 b 이하에 포함 여부 (이상~이하)
like / not like 문자열 패턴 비교
is null / is not null null 값 여부 비교
in / not in 비교 값 목록에 포함 여부 (기본적으로 or 연산)
 
and 좌항/우항의 논리 값이 모두 true인 경우, true 반환 / 나머지는 false
or 좌항/우항의 논리 값 중 하나라도 true인 경우, true 반환 / 나머지는 false
not 반전 (true를 false로, false를 true로)

☞ 동등비교

사원 테이블에서 부서 코드가 D6인 사원 조회 (사원명, 부서코드)

select
    emp_name 사원명,
    dept_code 부서코드
from
    employee
where
    dept_code = 'D6';

 

사원 테이블에서 부서 코드가 D6이면서 급여가 300만원 이상인 사원 조회 (사원명, 부서코드, 급여)

select
    emp_name 사원명,
    dept_code 부서코드,
    salary 급여
from
    employee
where
    dept_code = 'D6' and salary >= 3000000;

 

직급 코드가 'J1'이 아닌 사원의 급여 등급을 중복 없이 출력

select  distinct
    sal_level
from
    employee
where
    job_code != 'J1';   -- job_code <> 'J1" / job_code ^= 'J1' 모두 가능

 

부서 코드가 지정되지 않은 사원 조회 (사원명, 부서코드)

select
    emp_name 사원명,
    dept_code 부서코드
from
    employee
where
    dept_code is null;
--    dept_code = null;   -- null과는 어떤 연산 불가!!

여기서 dept_code = null을 한다면 결과 값은 null 일 것이고, null은 false를 반환하기 때문에 데이터가 나오지 않을 것입니다.

null을 비교할 때는 반드시 is null, is not null을 이용!!

 

 

☞ between a and b 연산자

- 범위에 포함되면 true를 반환

- a (작은 값) 이상 b (큰 값) 이하

- 숫자형 / 날짜형 처리 가능

 

급여가 350만원 이상 600만원 이하인 사원 조회 (사원명, 급여)

select
    emp_name 사원명,
    salary 급여
from
    employee
where
    salary between 3500000 and 6000000;
--   salary >= 3500000 and salary <= 6000000;	로도 대체가능

 

급여가 350만원 미만 또는 600만원 초과인 사원 조회 (사원명, 급여)

select
    emp_name 사원명,
    salary 급여
from
    employee
where
    salary not between 3500000 and 6000000; -- not salary between ..~ 도 가능
--    salary < 3500000 or salary > 6000000; -- 로도 대체가능

 

* 날짜 범위 연산

입사일이 90년 1월 1일 ~ 01년 01월 01일 사원을 조회 (사원명, 입사일)

select
    emp_name 사원명,
    hire_date 입사일
from
    employee
where   
    hire_date between '900101' and '010101';	 -- 날짜포맷의 문자열을 사용하면 자동으로 날짜형으로 변환 처리

yyyy/mm/dd

yy/mm/dd

yyyy-mm-dd

yymmdd

날짜 포맷의 문자열을 사용하면 자동으로 날짜형으로 변환 처리 해줍니다.

 

 

☞ like / not like 문자열 패턴 비교 연산자

- 비교하는 값이 지정한 패턴을 만족하는 경우 true를 반환

 

다음의 와일드 카드를 지원합니다.

% 0개 이상의 문자
_ 문자 1개와 매칭

 

전씨 사원 조회

select
    emp_name 사원명
from
    employee
where
--    emp_name like '전%';
    emp_name like '전__';

'전%'과 '전__'의 결과 값은 현재 동일하지만, '전%'와 '전__'의 차이는 분명하게 있습니다.

 

'전%' → '전' 다음 0글자 이상이 연결되는 경우. 전형돈(O), 전지연(O), 전(O), 전진(O), 전가라세(O)

'전__' → '전' 이후 _ 개수만큼 정확히 연결되는 경우. 전형돈(O), 전지연(O), 전(X), 전진(X), 전가라세(X)

 

현재 전씨 사원이 '전형돈', '전지연' 이기 때문에 동일한 결과가 출력됐을지라도 만일 사원명 중 '전진', '전가라세' 등이 있었다면 둘의 결과는 확연히 달랐을 것입니다.

 

이름에 '이'가 들어가는 사원을 모두 조회

select
    emp_name 사원명
from
    employee
where
    emp_name like '%이%';

 

이메일의 '_' 앞 글자가 3자리인 사원 조회

select
    emp_name 사원명, 
    email 이메일
from
    employee
where
--    email like '____%';    4글자 이상을 조회하게 됨
    email like '___\_%' escape '\';

만일 '_' 앞에 3글자를 나타내기 위해 email like '____' 으로 하게 된다면,

시스템은 우리가 이메일의 '_'를 나타내는 마지막 '_'를 자리수를 표현하는 '_'로 인식하게 되어 4글자 이상의 이메일을 출력하게 됩니다.

escape 문자를 나타내기 위하여 해당 문자 앞에 escape문자를 지정해주고, 해당 문자가 escape이라는 표시를 해줍니다.

이 때, escape문자는 자유롭게 지정 가능하지만, 데이터에 포함되지 않은 문자여야겠죠!

email like '___#_%' escape '#';
email like '___^_%' escape '^';

--escape 문자는 자유롭게 지정 가능

 

 

☞ in 값 목록 포함 여부 연산자

- 제시한 값 목록에 포함 되어 있으면 true

※ null 값인 컬럼은 in 연산에도, not in 연산에도 포함 되지 않음

 

부서코드가 D6, D8인 사원 조회 (사원명, 부서코드)

select
    emp_name 사원명,
    dept_code 부서코드
from
    employee
where
--    dept_code = 'D6' or dept_code = 'D8'; 으로도 표현가능
    dept_code in ('D6', 'D8');

 

부서코드가 D6, D8이 아닌 사원 조회 (사원명, 부서코드)

select
    emp_name 사원명,
    dept_code 부서코드
from
    employee
where
--    dept_code != 'D6' and dept_code != 'D8';
    dept_code not in ('D6', 'D8');

 

☞ 연산자 우선 순위

① 산술연산 / 연결연산

② 비교연산

③ 논리연산 (not → and → or)

 

부서코드가 D5 또는 D9이면서 급여가 270만원 이상인 사원 조회

-- 틀린 답!
select
    emp_name 사원명,
    dept_code 부서코드,
    salary 급여
from
    employee
where
    dept_code = 'D5' or dept_code = 'D9'
    and
    salary >= 2700000;

언뜻 보기에는 문제가 없는 로직일 수 있겠지만, 이렇게 하면 원하는 결과 값을 얻을 수 없습니다.

결과를 보면 급여가 270만원 이하인 사원들도 같이 출력 되는 것을 확인할 수 있습니다.

 

그 이유는 연산자 우선 순위 때문인데요.

논리 연산에서도 not - and - or의 우선 순위를 갖게 되어 우리의 의도인

(dept_code = 'D5' or dept_code = 'D9') and (salary >= 2700000) 이 아닌,

(dept_code = 'D5') or (dept_code = 'D9' and salary >= 2700000) 이렇게 처리하기 때문에 결과 값이 완전히 달라지게 되는 것이죠.

원하는 결과를 얻기 위해선 중괄호를 이용해 우선순위를 다시 정해줘야 합니다.

select
    emp_name 사원명,
    dept_code 부서코드,
    salary 급여
from
    employee
where
    (dept_code = 'D5' or dept_code = 'D9')
    and
    salary >= 2700000;


@실습문제

1. 이름이 '연'으로 끝나는 사원 조회

select
    emp_name 사원명
from
    employee
where
    emp_name like '%연';

 

2. 전화번호 첫 3자리가 010이 아닌 사원 조회

select
    emp_name 사원명,
    phone 전화번호
from
    employee
where
    phone not like '010%';

 

3. 부서코드가 D5 또는 D9이면서 급여가 270만원 이상인 사원 조회

select
    emp_name 사원명,
    dept_code 부서코드,
    salary 급여
from
    employee
where
    dept_code in ('D5', 'D9') 
    and 
    salary >= 2700000;

 

4. 직급코드가 J2 또는 J7이고, 입사일이 90/01/01 ~ 01/12/31이고, 급여가 300만원 이상인 사원 조회

select
    emp_name 사원명,
    job_code 직급코드,
    hire_date 입사일,
    salary 급여
from
    employee
where
    job_code in ('J2', 'J7')
    and
    hire_date between '90/01/01' and '01/12/31'
    and
    salary >= 3000000;

 

5. 부서코드가 null인 사원

-- is null 이용
select
    emp_name 사원명,
    dept_code 부서코드
from
    employee
where
    dept_code is null;
----------------------------------
-- nvl 이용
select
    emp_name 사원명,
    dept_code 부서코드
from
    employee
where
    nvl(dept_code, '인턴') = '인턴';

 

6. 부서코드가 null이 아닌 사원

-- is not null 이용
select
    emp_name 사원명,
    dept_code 부서코드
from
    employee
where
--    dept_code is null;
    dept_code is not null;
----------------------------------
-- nvl 이용
select
    emp_name 사원명,
    dept_code 부서코드
from
    employee
where
    nvl(dept_code, '인턴') != '인턴';