본문 바로가기
오라클

오라클 - WHERE절과 연산자에 대한 정리

by onggury 2023. 2. 7.

 

 

  지난번엔 SELECT에 관해 다뤄봤습니다.

 

 

SELECT문은 필수적으로 적어줘야 했는데 그 외 옵션들 중 WHERE절이 있었죠.

 

 

이번엔 WHERE 절에 대해 정리해보겠습니다.

 

 

단, 여기 정리한 글이 WHERE절의 전부는 아닙니다.

 

기본적인 것만 정리하였고 그 외에는 저도 추가 공부가 필요합니다 ㅠ

 

 


 

 

1. WHERE절

 

 

  프로그래밍을 하다보면 동등 연산자(==)을 많이 씁니다.

 

 

그런데 SQL에서는 다릅니다.

 

SQL에서는
동등 연산자가
"=" 하나다.

 

 

이걸 알고 이제 where절에 대해 정리 해보겠습니다.

 

 

 

지난 글에 SELECT에 대해 정리할 때, WHERE에 대한 얘기가 잠깐 나왔었죠.

 

다시 정리하자면, WHERE절은 간단히 말해, 프로그래밍 언어에서 if문에 속합니다.

 

 

 

if문은 특징이 뭔가요?

 

if문 다음에 조건식이 오고 그것을 참/거짓으로 판단하죠.

 

 

WHERE 절도 마찬가지입니다.

 

 

 

만약 이런 문제가 있습니다.

 

emp 테이블에서 업무가 'MANAGER' 인 사원의 이름, 업무를 출력해보세요.

 

 

 

한번 if문으로 생각해봅시다.

 

저 문제를 if문처럼 나타내면 어떨까요?

 

 

if(업무 == 'MANAGER') { ... }

 

이렇게 되겠죠.

 

 

 

그러면 WHERE절은 어떻게 표기가 될까요?

 

 

위에 동등연산자를 한번 생각해봅시다.

 

그러면 이렇게 되겠지요.

 

 

WHERE 업무 = 'MANAGER'

 

여기서 업무는 JOB 컬럼이니 이제 SELECT 문과 같이 위 문제에 대해 적는다면,

 

 

SELECT ename, job
FROM emp
WHERE job = 'MANAGER';

 

 

가 되겠습니다.

 

 

한번 더 정리하고 가자면,
반드시 SELECT -> FROM -> WHERE -> GROUP BY -> HAVING -> ORDER BY
순서로 구성되어야 합니다.
SELECT와 FROM 이외의 절은 옵션이니
필요에 따라서 사용하되,
순서는 지켜져야 합니다.

 

 

 

 

그러면 이제 좀 더 응용해서 문제를 보겠습니다.

 

 

emp 테이블에서 업무가 'MANAGER' 이거나 'ANALYST' 이고 급여가 2000 이상인 사원의 이름, 업무, 급여를 출력해보세요.

 

 

'이거나' 와 '이고' 가 나왔습니다.

 

 

조건에서 저 두 문장은 각각 'or' 와 'and' 를 뜻했죠.

 

WHERE 절에서도 똑같습니다.

 

 

그러면 밑에 보시기 전에 먼저 한번 위 문제를 풀어보세요.

.

.

.

.

.

.

.

.

.

 

 

혹시 무작정 이렇게 적으셨나요?

 

SELECT ename, job, sal
FROM emp
WHERE job = 'MANAGER' or job = 'ANALYST' and sal >= 2000;

 

결과를 볼까요?

 

 

 

 

 

어? 직책이 MANAGER 이면서 ANALYST이고
급여가 2000이상인 사람 잘 나왔는데요??

 

 

 

네 결과는 맞습니다.

 

 

그러나 if문의 특징을 한번 다시 생각해볼까요?

 

 

비교 연산자의 우선순위는 누가 우선인가요??

 

 

 

 

바로 and가 우선순위가 높죠.

 

우리는 업무가 'MANAGER' 이거나 'ANALYST' 이고 급여가 2000 이상인 사원을 원했는데, 현재 테이블이 저래서 다행이지만 만약 다른 온갖 정보가 수천 수만개가 있다고 가정하면, 자칫하다간 우선순위로 인해 결과가 엉망으로 출력되겠죠.

 

 

그래서 우리는 if문 처럼 우선순위를 위해 괄호를 해주는것이 좋습니다.

SELECT ename, job, sal
FROM emp
WHERE (job = 'MANAGER' or job = 'ANALYST') and sal >= 2000;

 

결과는 같습니다.

 

 

 


 

 

 

2. WHERE 절에서만 사용하는 SQL 연산자

 

 

 이번에는 WHERE절에서 사용하는 SQL 연산자를 한번 알아보도록 하겠습니다.

 

 

1) IN - 목록 연산자

2) BETWEEN A AND B - 범위 연산자

3) LIKE - 검색 연산자

4) IS NULL - null 값 비교 연산자

 

 

 

 

1) IN 목록 연산자

 

IN 연산자는 마치 or와 같습니다.

 

바로 예시를 보겠습니다.

 

 

SELECT ename, job, sal
FROM emp
WHERE job IN('CLERK', 'ANALYST');

 

위와 같이 job 컬럼에 대해 직책이 'CLERK' 이거나 'ANALYST' 인 사람을 출력하라는 뜻입니다.

 

 

 

 

 

and와 같이 써보겠습니다.

 

 

SELECT ename, job, sal
FROM emp
WHERE job IN('CLERK', 'ANALYST') and sal >= 2000;

 

 

 

직책이 'CLERK' 이거나 'ANALYST인 사람 중, 급여가 2000이상인 사람들이 잘 나온것을 볼 수 있습니다.

 

 

 

 

2) BETWEEN A AND B - 범위 연산자

 

 

  이 연산자는 A와 B도 포함합니다.

 

SELECT ename, job, sal
FROM emp
WHERE sal BETWEEN 2000 AND 3000;

 

 

 

 

그렇다면 이 연산자를 날짜 데이터에다가 적용시켜 볼까요?

 

 

82년도에 입사한 사원의 이름과 입사 날짜를 출력하는 쿼리를 작성하세요.

 

이것도 한번 작성해보시고 밑에 봐주세요.

.

.

.

.

.

.

.

.

.

 

 

SELECT ename, hiredate
FROM emp
WHERE hiredate BETWEEN '82/01/01' AND '82/12/31';

 

 

라고 잘 적으셨나요?

 

 

 

 

 

결과도 잘 나온것을 볼 수 있습니다.

 

 

 

하지만 이것은 틀렸습니다(중요).

 

날짜 데이터는 시간 값을 생략하는 경우 시간은 자동으로 0시 0분 0초가 됩니다.

 

 

그러면 82/01/01 ~ 82/12/31은 무슨 뜻 일까요?

 

 

"82년 01월 01일 0시 0분 0초 ~ 82년 12월 31일 0시 0분 0초" 라는 뜻이죠.

 

 

그러면 82년 12월 31일 오후 2시 30분에 들어온 사원은 82년도에 들어온 사원이 아닌가요?

 

 

이러한 문제 때문에 저렇게 쓰면 틀린 답이 됩니다.

 

즉 우리는 날짜 함수를 쓰거나 83/01/01 까지 범위를 지정해줘야만 합니다.

 

 

날짜 함수는 다음번에 다루겠습니다.

 

 

 

 

3) LIKE - 검색 연산자

 

 

  검색 연산자는 어떤 문자열이 포함된 정보의 데이터를 조회할 때 사용합니다.

 

 

바로 예시를 보겠습니다.

 

SELECT ename
FROM emp
WHERE ename LIKE '%A%';

 

 

LIKE 뒤에 'A'도 아니고 무슨 %까지 써가면서 표시를 해줬습니다.

 

 

저 뜻은 '앞이나 뒤나 상관없이 어디든 A가 들어가던 그걸 출력해 줘' 라는 뜻입니다.

 

 

 

결과도 보시면 'A' 가 어떤 위치에 있던 전부 출력해줬죠.

 

 

그러면 'A%' 라고 하면 어떨까요?

 

 

SELECT ename
FROM emp
WHERE ename LIKE 'A%';

 

 

 

 

이와 같이 '앞이 A인것만 출력해 줘, 뒤는 뭐던 상관없어' 라고 말하는 것 입니다.

 

그러면 '%A' 는 앞이 뭐던간에 맨 뒤가 A인 것만 출력해달라는 뜻이 되겠지요.

 

 

 

이처럼 %기호는 '와일드 카드' 라고 합니다.

 

와일드 카드는 '특정 문자 또는 문자열을 대체하거나 문자열 데이터의 패턴을 표기' 하는 특수 문자입니다.

 

 

이러한 와일드 카드는 %기호 외에 _(언더 바)기호도 있습니다.

 

_(언더바) 기호는 어떤 값이든 상관없이 한 개의 문자를 뜻합니다.

 

 

무슨뜻이냐면,

 

 

 

SELECT ename
FROM emp
WHERE ename LIKE '_L%';

 

 

%기호는 이제 뭔 뜻인지 알겠죠.

언더바 기호를 빼고 보자면, '뒤는 뭐가 되었던 상관없으니 L인 문자가 들어간 것을 찾아줘' 라는 뜻이 됩니다.

 

 

_기호는 어떤 값이든 상관없이 한 개의 문자를 뜻한다고 했습니다.

 

즉, L뒤에 C가오던 ㄱ이 오던 뭐... 9가 오던 상관없이 그 다음이 L인 문자인 것을 찾아달라 라는 뜻이지요.

 

 

결과를 봅시다.

 

 

 

앞이 A던 B던 C던 상관없이 두 번째가 L인 정보를 찾았습니다.

 

 

'%L_'은 그 반대가 되겠지요.

 

 

 

L은 없는것 같아서 R문자에 대해 적용해보았습니다.

 

 

 

 

 

4) IS NULL - null 값 비교 연산자

 

 

  null 값은 값 자체가 없기 때문에 어떤 연산이던 연산이 되질 않습니다.

 

즉, comm = null 하면 값이 하나도 안나옵니다.

 

 

 

 

따라서 IS NULL 연산자를 사용해서 null값을 찾아야 합니다.

 

 

SELECT ename, job, sal, comm
FROM emp
WHERE comm IS NULL;

 

comm 이 null 값인 정보만 출력

 

comm 이 null 값인 정보까지 전부 출력

 

 

비교해보시면, comm 값을 가진 정보는 세일즈맨 4명 빼곤 전부 null값입니다.

 

 

그래서 결과도 총 14 rows 중 10 rows 만 나온 것을 볼 수 있습니다.

 

 

 

 


 

 

 

3. NOT 연산자

 

 

NOT 연산자는 조건의 결과를 반대로 해주죠.

true 는 false로

false 는 true로

 

 

 

이처럼 NOT 연산자를 이용해서 여기저기 적용할 수 있습니다.

 

 

 

 

1) NOT IN

 

먼저 위에서 썼던 IN 연산자를 보겠습니다.

SELECT ename, job, sal
FROM emp
WHERE job NOT IN('CLERK', 'ANALYST') and sal >= 2000;

 

IN 앞에 NOT을 붙임으로써 직책이 CLERK, ANALYST가 아닌 사원의 정보를 찾습니다.

 

 

 

 

 

 

2) NOT LIKE

 

 

NOT LIKE를 이용해 '이름의 두번째가 A가 아닌 사원의 정보'를 출력해보겠습니다.

 

 

SELECT ename
FROM emp
WHERE ename NOT LIKE '_A%';

 

 

 

와일드 카드를 이용해 이름 두번째가 A가 아닌 사원의 정보가 출력되었습니다.

 

 

 

 

3) NOT BETWEEN  A  AND B

 

 

 

NOT을 이용해 '급여가 2000대가 아닌 사원의 정보를 찾아보겠습니다.

 

SELECT ename, sal
FROM emp
WHERE sal NOT BETWEEN 2000 and 2999;

 

 

 

 

4) IS NOT NULL

 

※ NOT IS NULL 이 아님을 주의합니다.

 

 

null값이 아닌 정보들을 찾습니다.

 

SELECT ename, job, sal, comm
FROM emp
WHERE comm IS NOT NULL;

 

comm이 null값이 아닌 사원은 세일즈맨 4명 뿐이였죠.

 

 

 

그래서 결과도 4명이 나온것을 볼 수 있습니다.

 

 

 

 


 

 

 

4. 집합 연산자

 

 

1.1) union : 암시적 DISTINCT 가 걸려서 동일한 값은 제거가 된다.

 

 

DISTINCT는 SELECT문을 살펴볼 때, 중복값은 제거해주는 것을 봤었죠.

 

union 연산자도 DISTINCT로 중복을 빼고 두 쿼리를 엮어서 보여줍니다.

 

 

SELECT deptno FROM dept
UNION
SELECT deptno FROM emp;

 

 

dept 테이블과 emp 테이블에 있는 deptno(부서 번호)를 출력하는데, Union 연산자를 써서 중복된건 빼고 보여달라는 뜻입니다.

 

 

전에 emp 테이블을 살펴봤을 때, 10, 20, 30 부서밖에 없었죠.

 

하지만 저렇게 쓰면 dept 테이블의 부서 번호까지 합해서 중복 제거 후 출력해주기 때문에 부서 번호 40까지 나온 것을 확인할 수 있습니다.

 

 

 

또한,

컬럼의 개수가 안맞을 땐, 작은 따옴표로 ' ' 공백을 주어 표기해도 되긴 합니다.

그러나 컬럼 명이 ' ' 공백이 나오기 때문에 컬럼 명을 칭해야 합니다.

 

 

SELECT deptno, ' ' FROM dept
UNION
SELECT deptno, ename FROM emp;

컬럼 명이  ' ' 공백으로 나온 모습

 

SELECT deptno, ' ' as "test" FROM dept
UNION
SELECT deptno, ename FROM emp;

 

 

그러면 반대로 두번째 쿼리에 공백을 주면 어떨까요?

 

 

SELECT deptno, dname FROM dept
UNION
SELECT deptno, ' ' FROM emp;

 

 

 

두 번째 쿼리에 공백을 주었음에도 컬럼 명이 제대로 나온것을 볼 수 있습니다.

 

 

즉, 첫 번째 쿼리에서 컬럼의 해딩을 결정합니다.

 

이것도 중요한 내용이니 알아두셨으면 합니다.

 

 

 

 

1.2) union all : 두 쿼리를 중복 포함해서 출력한다.

 

 

말 그대로 중복을 포함해서 전부 출력해줍니다.

 

 

SELECT deptno FROM dept
UNION ALL
SELECT deptno FROM emp;

 

 

 

 

dept 테이블의 4개의 행과, emp 테이블의 14개 행 두개를 더해서 총 18개의 행이 나왔네요.

 

 

 

 

2) Intersect : 교집합

 

 

이것도 말 그대로 두개의 쿼리를 교집합 해서 나옵니다.

 

SELECT empno, ename, sal, deptno FROM emp
INTERSECT
SELECT empno, ename, sal, deptno FROM emp
WHERE deptno = 10;

 

 

emp 테이블을 통해 봅시다.

 

empno, ename, sal, deptno에 대해서 교집합을 수행하는데,

두번째 쿼리는 그 중, deptno값이 10인 값을 출력합니다.

 

이 두개의 쿼리를 교집합을 하니 deptno인 값은 10인 사원의 정보들이 나오겠죠.

 

 

 

 

근데, 이렇게 적어도 출력이 잘 될까요?

SELECT empno, sal, deptno , ename FROM emp
INTERSECT
SELECT empno, ename, sal, deptno FROM emp
WHERE deptno = 10;

 

 

첫 번째 쿼리의 컬럼 순서를 섞었습니다.

 

 

결과적으로 

 

오류입니다.

 

 

이는 같은 종류의 타입이여야 하며, 컬럼의 개수 또한 일치해야 한다는 주의점이 있습니다.

sal과 ename은 타입이 다르기에 오류가 나오죠.

 

 

 

타입이 같더라도 컬럼 순서가 서로 다르면 값이 다르게 나옵니다.

SELECT empno, ename, deptno, sla FROM emp
INTERSECT
SELECT empno, ename, sal, deptno FROM emp

 

deptno과 sal은 타입이 같아서 오류는 나지 않지만, 순서가 달라서 제대로된 값이 안나오는 것을 볼 수 있습니다.

 

 

 

 

 

3) Minus : 차집합

 

 

 

두 쿼리에 대해 차집합을 진행해서 출력합니다.

 

 

SELECT empno, ename, sal, deptno FROM emp
MINUS
SELECT empno, ename, sal, deptno FROM emp
WHERE deptno = 10;

 

두 쿼리에 대한 차집합 결과
두 번째 쿼리

 

 

두 쿼리 결과 값이 같은 데이터는 제외하고 첫 번째 쿼리 결과 값이 출력됩니다.

 

 

차집합 특성상 위 커리에서 아래 쿼리를 차집합 하기 때문에 순서에 따라 값이 다를 수 있으니 주의해야 합니다.

 

 

 

 

여기까지 WHERE절과 그와 관련된 연산자에 대해 정리해 보았습니다.