필터링

골머리·2021년 11월 9일
0

MySQL

목록 보기
6/16

필터링 = 조건이다.
엑셀에서 "이런 값을 가진 데이터만 보고싶어" 할 때 필터기능을 쓰는걸 생각하자.
select, update, delete 문의 WHERE 절에서 사용할 수 있는 다양한 필터조건을 알아보자.

조건 평가

  • ANDOR 를 통해 하나 이상의 조건을 포함시킬 수 있다.
  • 조건이 3개 이상 포함될 경우, 괄호( )를 써서 의도를 명확히 하자.
  • 조건을 쓸 때는 값 = 조건 의 형태로 쓰자.
  • WHERE NOT<>와 같다.
WHERE NOT 
	(first_name = 'STEVEN' OR last_name = 'YOUNG')
    AND create_date > '2006-01-01'

이 쿼리는 <>를 이용하여 아래 쿼리처럼 쓸 수도 있다.

WHERE 
	first_name <> 'STEVEN' 
	AND last_name <> 'YOUNG'
	AND create_date > '2006-01-01'

아래 쿼리가 사람이 이해하기에 좀더 쉽다.
→ first_name이 'steven'이 아닌 사람
그리고 last_name이 'young'이 아닌 사람
그리고 2006년 1월 1일 이후에 생성된

조건 작성

조건은 1개 이상의 연산자와 1개 이상의 표현식으로 구성된다.

표현식

  • 숫자
  • 테이블 또는 뷰의 열
  • 문자열 (예: Maple Street)
  • 내장함수 (예: concat('Learning', ' ', 'SQL'))
  • 서브쿼리
  • 표현식 목록 (예: ('Boston','New York','Chicago'))

[참고] 내장함수를 확인해보고 싶을 때

내장함수를 확인해보고 싶을 때는 아래와 같이 from dual을 활용하면 된다.
예를 들어, concat 함수가 어떻게 작동하는지 궁금하다 하면

SELECT concat('Hello',' ','World!') 
FROM DUAL;

연산자

  • 비교 연산자 : =, !=, <, >, <>, like, in, between
  • 산술 연산자 : +, -, *, /

조건 유형

동등조건

= 연산자를 사용한다.

= 표현/

부등조건

!=, <> 연산자를 사용한다.

동등/부등조건을 사용한 데이터변경

동등/부등조건은 보통 데이터를 수정할 때 사용한다.
예를 들어, 오래된 계정을 삭제하는 정책이 있고, 그 때문에 rental 테이블에서 대여날짜가 2004년인 행을 삭제해야 한다고 가정해보자.

DELETE FROM rental
WHERE year(rental_date) = 2004 ;

혹은 대여날짜가 2005년이나 2006년이 아닌 행을 삭제해야 한다면?

DELETE FROM rental
WHERE year(rental_date) <> 2005
  AND year(rental_date) <> 2006 ;

범위조건 : Between ... AND, 문자열 범위

해당 식이 특정 범위 내에 있는지를 확인한다.
보통 숫자나 시간 데이터로 작업할 때 발생한다.
<=, <, >, >= 등의 연산자로 범위를 지정할 수 있다.

between ... and 연산자

  • 항상 범위의 하한값을 먼저 지정하고, 상한값을 두번째로 지정해야 한다.
  • 지정한 상한값과 하한값이 범위에 포함되어 결과로 나타난다.
    • 예를 들어 2005-06-14를 범위의 하한으로 지정하고, 2005-06-16을 범위의 상한으로 지정하면 시간은 기본적으로 자정으로 설정된다.

문자열 범위

  • 문자열 범위를 사용하기 위해서는 캐릭터셋의 문자 순서를 알아야 한다.
    • 이때, 캐릭터셋의 문자가 정렬되는 순서 규칙을 콜레이션(collation) 이라고 한다.

멤버십조건 : OR, IN, NOT IN 사용하기

예를 들어, 영화같은 경우 관람등급이 나누어져 있다.
정해진 값의 범위가 있을 경우 동등조건 또는 IN 연산자를 사용할 수 있다.
예를 들어, 관람등급이 'G' 또는 'PG'인 영화만 보고싶을 경우 아래와 같은 쿼리로 해당 영화를 찾을 수 있다.

조건이 막 10개 이상으로 많아지게 되면 OR을 사용하는게 오히려 비효율적일 수 있다.
이때 IN을 사용한다.

SELECT title, rating
FROM film 
WHERE rating='G'
   OR rating='PG';
   
또는

SELECT title, rating
FROM film
WHERE rating 
   IN ('G', 'PG');

NOT IN 사용하기

어떤 표현식이 "안 존재하는지" 여부를 확인하고 싶을 때 사용한다.
예를 들어, 'R', 'PG-13', 'NC-17' 등급이 아닌 영화를 찾고 싶다면

SELECT title, rating
FROM film
WHERE rating NOT IN ('R', 'PG-13', 'NC-17');

일치조건 : 와일드카드, LIKE 구문, 정규표현식(REGEXP) 사용하기

부분 문자열이 일치하는 데이터를 확인하고 싶을 때 사용한다. (예를 들면 'K'로 성이 시작하는 모든 사람을 검색하고 싶다거나)

와일드카드 사용

  • 특정 문자로 시작 또는 종료하는 문자열
  • 부분 문자열로 시작 또는 종료하는 문자열
  • 문자열 내에 특정 문자를 포함하는 문자열
  • 문자열 내에 부분 문자열을 포함하는 문자열
  • 개별 문자에 관계없이 특정 형식의 문자열

LIKE 구문 사용하기

  • _ : 글자숫자를 정해줌 (EX 컬럼명 LIKE '홍_동') , 정확히 1개 문자.
  • % : 글자숫자를 정해주지않음 (EX 컬럼명 LIKE '홍%') , 가변 문자.
--A로 시작하는 문자를 찾기--
SELECT 컬럼명 FROM 테이블 WHERE 컬럼명 LIKE 'A%'

--A로 끝나는 문자 찾기--
SELECT 컬럼명 FROM 테이블 WHERE 컬럼명 LIKE '%A'

--A를 포함하는 문자 찾기--
SELECT 컬럼명 FROM 테이블 WHERE 컬럼명 LIKE '%A%'

--A로 시작하는 두글자 문자 찾기--
SELECT 컬럼명 FROM 테이블 WHERE 컬럼명 LIKE 'A_'

--첫번째 문자가 'A''가 아닌 모든 문자열 찾기--
SELECT 컬럼명 FROM 테이블 WHERE 컬럼명 LIKE'[^A]'

--첫번째 문자가 'A'또는'B'또는'C'인 문자열 찾기--
SELECT 컬럼명 FROM 테이블 WHERE 컬럼명 LIKE '[ABC]'
SELECT 컬럼명 FROM 테이블 WHERE 컬럼명 LIKE '[A-C]'

연습

last_name LIKE '_A_T%S'

→ 문자의 두번째 위치가 A이고, 네번째 위치가 T이고, 마지막이 S로 끝나는 성(lastName)을 찾을 것이다.

정규 표현식 사용 : REGEXP

like 연산자와 함께 정규식을 사용할 수 있다.
성이 Q 또는 Y로 시작하는 고객을 찾고 싶을 때,

[방법1] LIKE 사용:
SELECT last_name, first_name
FROM customer
WHERE last_name LIKE 'Q%' 
   OR last_name LIKE 'Y%' ;
   
[방법2] 정규표현식(REGEXP) 사용:
SELECT last_name, first_name
FROM customer
WHERE last_name REGEXP '^[QY]' ;

Null

  • null일수는 있지만, null과 같을 수는 없다.
  • 두개의 null은 서로 같지 않다.

값이 null인 데이터를 확인하려면 IS NULL 을 사용하면 된다.
반대로 값이 열에 할당되었는지를 확인하려면 IS NOT NULL을 사용한다.


주석 : 책에서 이상한 부분 ...

한빛미디어의 'Learning SQL' 로 공부중인데, "4장 필터링" 마지막에 이상한 부분이 있어서 혼란스러웠다.

  • 이상한 부분: p122~125

2005년 5월 ~ 8월 사이에 반납되지 않은 모든 DVD 대여정보를 찾고싶다고 가정했을 때, 아래 쿼리는 불완전하다고 지적했다.

불완전 : 

SELECT rental_id, customer_id, return_date
FROM rental
WHERE return_date NOT BETWEEN '2005-05-01' AND '2005-09-01' ;
----------
62 rows in set

왜냐하면 이렇게 쿼리를 작성하면 반납되지 않은 DVD가 아니고, 5~8월이 아닌 날짜에 "반납된" DVD 리스트가 보여질 것이기 때문이다.
따라서, null이 포함된 아래와 같은 쿼리를 써야 한다고 나와있는데......

올바른 쿼리????? : 

SELECT rental_id, customer_id, return_date
FROM rental
WHERE return_date IS NULL
   OR return_date NOT BETWEEN '2005-05-01' AND '2005-09-01' ;
----------
245 rows in set

이렇게 되면 5~8월이 아닌 날짜에 "반납된" DVD 리스트(62개)와, 아직 반납되지 않은 DVD리스트(183개)까지 함께 보여질 것이다.
따라서 원래 구하고 싶은 5~8월 사이에 반납되지 않은 DVD 정보는 아니라는거다.
왜냐하면 아직 반납되지 않은 DVD 리스트(183개)는 DVD가게를 처음 열었을 때부터 지금까지 반납되지 않은 모든 DVD일거기 때문이다.

만약 5~8월 사이 반납되지 않은 리스트를 구하고 싶다면

  • rental 테이블에서 rental_date와 film 테이블에서 rental_duration을 이용해 "반납해야할 날짜"를 구한다음,
  • "반납해야할 날짜"가 5~8월 사이인데 return_dateNULL인 데이터를 찾아야하는게 맞지 않나...

왜냐면 return_date는 반납해야할 날짜가 아니고, 실제로 고객이 반납한 날짜이기 때문이다.
따라서 2005년 5~8월 사이에 반납되지 않은 DVD 대여정보를 찾기에는 rental 테이블만으로는 어려워보인다.

암튼 필터링 끝 😊 이제 실습해보기로 한다.

profile
PO로 성장하기 위해 노력 중 👩🏾‍💻

0개의 댓글