데이터 처리/SQL

[MySQL] 조건에 맞는 데이터 조회하기(WHERE절), 정렬하기(ORDER BY절)

yourhm 2022. 5. 4. 13:51

조건에 맞는 데이터 조회하기

WHERE 절을 사용하여 조건을 생성할 수 있다.

 

<WHERE 조건 유형 8가지 정리>

 

구분 설명  대표 예시 / 키워드
1. 값 일치 / 불일치 특정 값과 일치 여부 확인 =, !=, <>WHERE status = 'Active'
2. 포함 / 제외 여러 값 중 포함 여부 확인 IN (...), NOT IN (...)WHERE type IN ('Cat', 'Dog')
3. 범위 특정 값이 일정 범위 안/밖에 있는지 BETWEEN, NOT BETWEENWHERE age BETWEEN 1 AND 10
4. 비교 크거나 작음 비교 <, >, <=, >=WHERE score > 90
5. 문자열 패턴 일치 / 불일치 문자열이 특정 패턴과 일치하는지 LIKE, NOT LIKEWHERE name LIKE 'A%'
6. 결측값 (NULL) 값이 비어 있는지 (NULL) 여부 IS NULL, IS NOT NULLWHERE phone IS NULL
7. 조합 조건 여러 조건을 함께 사용 AND, OR, NOT, 괄호 ()WHERE age > 18 AND gender = 'F'
8. 존재 조건 서브쿼리 결과 존재 여부 EXISTS, NOT EXISTSWHERE EXISTS (SELECT ...)

 

 

 

1. 비교연산자 사용하여 조건 만들기 

=, <>, ≤, ≥, <, >

 

SELECT *
FROM Products
WHERE ProductName < "C"

숫자뿐만 아니라 문자에 대해서도 비교연산자를 사용할 수 있다.

위 예시와 같은 쿼리를 실행한다면, 알파벳 순서에 따라서 문자 "C" 이전에 오는 데이터들만 불러온다. ProductName이 "A", "B" 로 시작하는 모든 데이터를 조회한다.

 

 

2. 논리연산자 사용하여 여러 조건 결합하기

더 구체적인 조건을 만들기위해 논리연산자를 사용하여 여러 조건들을 결합할 수 있다.

 

 

 

(1) AND

SELECT *
FROM Products
WHERE ProductsName < "C"
  AND Category = "Furniture"

 

 

(2) BETWEEN A AND B

: BETWEEN 조건에 써준 시작 값(A)과 끝 값(B)를 포함한다 : A이상 ~ B이하

 

 ⇒ 한 컬럼에 대해 특정 범위 또는 기간을 나타내야할 때, AND로 두 조건을 나타내는 대신 'BETWEEN' 으로 대체할 수 있다.

-- (1) AND를 사용할 때
SELECT *
FROM Products
WHERE ProductID >= 10 AND ProductID <= 20

-- (2) BETWEEN을 사용할 때: 더 간결함
SELECT *
FROM Products
WHERE ProductID BETWEEN 10 AND 20

 

단, 날짜에 대해 조건을 설정할 때는 데이터 타입에 따라 주의 필요!

 

(1) 조건을 설정할 컬럼이 DATE 타입인 경우

BETWEEN '2024-01-01' AND '2024-01-31' 👉 1/1 ~ 1/31 (즉 1/31 까지 포함된다)

 

(2) 조건을 설정할 컬럼이 DATETIME 또는 TIMESTAMP 타입인 경우

BETWEEN '2024-01-01' AND '2024-01-31' 👉 1/1 ~ 1/30, 1/31 00:00:00 (완벽하게 포함되는 마지막 날짜는 1/30)

 

왜냐하면 DATETIME 또는 TIMESTAMP 타입의 경우 날짜뿐만 아니라 시간도 포함되어 있기 때문에, BETWEEN에 시간도 함께 정확히 표시를 해 주어야 한다. 저렇게 날짜만 표시해주면 시간 부분은 임의로 00:00:00 라고 여기기 때문에 2024-01-31 00:00:00 을 1초라도 지난 대부분의 1/31 의 데이터는 포함되지 않는다. 그래서 1/31까지 포함하고 싶다면 시간도 포함하여 표시해주는 것이 좋다. 

 

'2024-01-01' ⇒ '2024-01-01 00:00:00'

'2024-01-31' '2024-01-31 00:00:00'

 

 

 

(3) OR

SELECT *
FROM Products
WHERE ProductsName < "C"
   OR ProductsName < "D"

 

 

(4) IN

 

CASE 1.

WHERE col_name IN (’A’, ‘B’, ‘C’)

 

⇒ 한 컬럼에 대해 OR을 사용한 조건이 여러 개 있을 때, 'IN' 을 사용할 수 있다. 예를 들어 'Category' 컬럼의 값들 중에서 여러 개의 카테고리에 대해 조회해야 할 때, 논리연산자 OR을 이용하여 조건을 계속 결합한다면 구문이 너무 길어지게 된다. 이때 IN을 사용함으로써 간결하게 작성할 수 있다.

 

-- (1) OR을 사용할 때
SELECT *
FROM Products
WHERE Category >= 'Furniture' OR Category <= 'Food'

-- (2) IN을 사용할 때: 더 간결함
SELECT *
FROM Products
WHERE Category IN ('Furniture', 'Food')

 

 

CASE 2. 

WHERE 'A' IN (col_name1, col_name2, col_name3)
 
WHERE 매칭할 조건 IN (컬럼1, 컬럼2, 컬럼3) 이렇게도 쓸 수 있음.

 

SELECT *
FROM Products
WHERE 3820 IN (employee_id, manager_id)

 

 

 

💡예제

상품 테이블에서 책이 10,000원이거나, 음식이 20,000원이거나, 옷이 30,000원 인 상품들을 모두 조회하고 싶은 경우 코드를 어떻게 작성해야 원하는 결과를 조회할 수 있을까?

 

'두 개 이상의 컬럼 값의 조합'에 대해 OR 조건을 생성하려는 경우이기 때문에, 카테고리와 가격 두 컬럼의 값을 조합하여 OR 조건을 생성해야 한다.

 

-- 잘 작성된 코드

SELECT *
FROM Products
WHERE (Category, Price) IN (('Book',10000), ('Food',20000), ('Fashion',30000))

이 쿼리는 (Category, Price)의 조합이 ('Book', 10000), ('Food', 20000), ('Fashion', 30000) 중 하나인 경우에만 행을 반환한다. 따라서 기대한 결과에 대해서 정확히 조회할 수 있다.

 

-- 잘못 작성된 코드

SELECT *
FROM Products
WHERE Category IN ('Book', 'Food', 'Fashion') AND Price IN (10000, 20000, 30000)

그러나 이렇게 한 컬럼씩 IN으로 조건을 만들고 그것을 AND로 결합하면 기대한 결과를 반환하지 않는다. 이 쿼리는 Category와 Price가 각각의 값에 대해 조합될 수 있는 모든 경우의 수를 반환한다. 즉, 아래와 같이 모든 조합에 대해서 모두 조회된다.

 

Book - 10000, Book - 20000, Book - 30000,

Food - 10000, Food - 20000, Food - 30000,

Fashion - 10000, Fashion - 20000, Fashion - 30000

 

 

 

3. 결측값 조회하기

SELECT *
FROM Products
WHERE ProductID IS NULL

IS NULL, IS NOT NULL

• 숫자도 아니고 문자도 아닌, 비어있는 값들을 조회할 수 있다.

 = NULL (X), <> NULL (X)  ⇒  비교연산자로 사용하지 않기 주의!

 

  O X
결측값이다 IS NULL = NULL
결측값이 아니다 IS NOT NULL <> NULL

 

 

 

4. 불일치 or 제외하는 조건 만들기

SQL에서 WHERE 절은 조건이 TRUE인 행만 반환하기 때문에, UNKNOWN인 경우 해당 행은 제외된다.

SQL에서 NULL은 어떤 값과 동일하지도 다르지도 않은 상태(UNKNOWN: 알 수 없음" 또는 "정의되지 않음")이기 때문에 제외된다. 

 

NULL = 'Aged' → FALSE가 아니라 UNKNOWN
NULL != 'Aged' → TRUE가 아니라 UNKNOWN
NULL NOT IN ('Aged') → TRUE가 아니라 UNKNOWN

 

이처럼 SQL에서 무언가를 불일치/제외하는 조건을 만들 때는 일치/포함하는 조건보다 주의해야 한다. NULL과의 관계에서 예상치 못한 결과가 생길 수 있기 때문이다.

 

[예시] 예를 들어 아래와 같은 데이터에서, 층수가 3층인 경우를 제외한 모든 데이터를 출력하고 싶은 경우라고 해보자.

cafe_id name floor
1 한강카페 1
2 강릉카페 2
3 서울카페 3
4 낙동강카페 NULL
5 제주도카페 1

 

-- 잘못 작성한 경우 (1)
SELECT *
FROM cafes
WHERE floor != 3

-- 
SELECT *
FROM cafes
WHERE floor NOT IN (3)

 

→ floor가 3이 아닌 경우를 출력하라는 쿼리는 맞지만, 지금과 같이 floor 컬럼에 NULL이 있는 경우에는 결과에 NULL이 포함되지 않는다. 이렇게 작성하면 (한강카페, 강릉카페, 제주도카페) 총 3개만 출력될 것이다.

 

-- 알맞게 작성한 경우
SELECT *
FROM cafes
WHERE floor != 3 OR floor IS NULL

 

  만약 NULL도 결과에 포함하고 싶다면 위와 같이 명시적으로 포함 조건을 작성해야 한다. 이렇게 작성하면 (한강카페, 강릉카페, 낙동강카페, 제주도카페) 총 4개가 출력될 것이다.

 

[참고] SQL에서 제외 조건을 만드는 방법


📌 기본적인 제외 조건 구문

제외 방식 예시 SQL 의미
!= 또는 <> WHERE status != 'Complete' Complete가 아닌 행 선택
NOT IN (...) WHERE type NOT IN ('Cat', 'Dog') Cat과 Dog을 제외한 나머지 선택
NOT LIKE WHERE name NOT LIKE 'A%' A로 시작하지 않는 이름 선택
NOT EXISTS WHERE NOT EXISTS (SELECT ...) 서브쿼리 결과가 없을 때만 선택
NOT BETWEEN WHERE age NOT BETWEEN 1 AND 10 1~10세 범위 선택

 

 

 

 

 

 

정렬하기

ORDER BY 컬럼명

• ASC: 오름차순 (default)

 DESC: 오름차순

 

SELECT *
FROM Products
WHERE Price < 50
ORDER BY ProductID DESC

 

- ORDER BY 의 위치는 항상 SELECT, FROM, WHERE 뒤에 온다.

- ORDER BY 는 데이터를 조회하는 명령어일뿐, 데이터베이스의 저장된 순서를 변경하는것이 아니다.

- 데이터 타입에 따른 대소 비교 차이

     ㄴ 수치형 데이터 정렬시 → 크기 순서로 대소 비교

     ㄴ 문자열 데이터 정렬시 → 사전식 순서(lexicographically)로 대소 비교

 

 

💡그렇다면 숫자가 들어있지만 문자열 타입(VARCHAR)으로 저장되어 있는 컬럼을 정렬하면 어떻게 될까?

문자열 타입으로 저장되어있기 때문에 아래에서 왼쪽과 같이 사전식 순서로 대소가 비교되어 정렬된다. 이런 경우 크기 순서로 정렬하고 싶다면 이렇게 적어주면 된다. ➡️ ORDER BY 컬럼명*1