본문 바로가기

DB

[DB] SQL – 조회, 필터링, 정렬 (WHERE, ORDER BY, LIMIT)

데이터베이스에 데이터를 저장하는 것만큼 중요한 것은, 저장된 데이터를 원하는 조건에 맞게 조회하고, 의미 있는 순서로 정렬하여 가치 있는 정보로 만드는 것입니다. 이 모든 작업의 중심에는 SELECT 문이 있다.

 


📌 SELECT와 FROM: 조회문의 기본 뼈대

 

SELECT 문은 두 가지 핵심 요소로 시작한다.

  • SELECT: 조회할 열(Column)을 지정 (무엇을 가져올 것인가?)
  • FROM: 데이터가 들어있는 테이블(Table)을 지정 (어디에서 가져올 것인가?)

가장 기본적인 형태는 * 와일드카드를 사용하여 테이블의 모든 열을 조회하는 것이다.

SELECT * FROM customers;

 

하지만 실무에서는 성능 저하가독성 문제를 피하기 위해, * 대신 필요한 열의 이름만 명시적으로 지정하는 것이 좋다.

또한, AS 키워드를 사용하여 열 이름에 '고객명'과 같은 별칭(Alias)을 붙이면 가독성을 크게 향상시킬 수 있다.

SELECT
    name AS 고객명,
    email AS 이메일
FROM
    customers;

 

별칭에 공백과 같은 특수 문자를 포함하려면 백틱(`)으로 감싸주면 된다.

SELECT
    name AS `상품 이름`,
    stock_quantity AS `남은 수량`
FROM
    products;

 


📌 WHERE: 원하는 데이터만 골라내기 (필터링)

 

WHERE 절은 FROM 절 뒤에 위치하며, 테이블의 전체 데이터 중 특정 조건을 만족하는 행(Row)만 걸러내는 필터 역할을 한다.

 

=, !=, >, < 등의 비교 연산자와 AND, OR, NOT 같은 논리 연산자를 조합하여 복잡한 조건을 만들 수 있다.

-- 가격이 5000원 이상이면서, 재고가 50개 이상인 상품 조회
SELECT * FROM products
WHERE price >= 5000 AND stock_quantity >= 50;

 

SQL은 더 간결하고 직관적인 검색을 위해 다음과 같은 유용한 연산자들을 제공한다.

  • BETWEEN a AND b: ab 사이의 값(양 끝 값 포함)을 검색한다.
  • IN (목록): 괄호 안의 목록 중 하나라도 일치하는 값을 검색한다. (여러 OR 조건을 사용하는 것보다 훨씬 가독성이 좋다.)
  • LIKE: 문자열의 일부 패턴으로 검색할 때 사용하며, %(0개 이상의 모든 문자)와 _(정확히 한 개의 문자) 와일드카드와 함께 사용된다.
  • IS NULL: 값이 NULL인 데이터를 찾는다.
SELECT * FROM products WHERE price BETWEEN 5000 AND 15000;
SELECT * FROM products WHERE price NOT BETWEEN 5000 AND 15000;

SELECT * FROM products WHERE name IN ('갤럭시', '아이폰', '에어팟');
SELECT * FROM products WHERE name NOT IN ('갤럭시', '아이폰', '에어팟');

SELECT * FROM customers WHERE name LIKE '김_연';
SELECT * FROM customers WHERE address NOT LIKE '서울%';

SELECT * FROM products WHERE description IS NULL;
SELECT * FROM products WHERE description IS NOT NULL;

 


📌 ORDER BY: 결과 정렬하기

 

ORDER BY 절은 SELECT 문의 가장 마지막에 위치하며, 조회된 결과를 특정 열 기준으로 정렬한다.

ORDER BY를 명시하지 않으면 결과의 순서는 보장되지 않는다.

 

  • ASC (Ascending): 오름차순 (기본값이므로 생략 가능)
  • DESC (Descending): 내림차순
  • 다중 열 정렬: 콤마(,)로 여러 열을 나열하여 1차, 2차 정렬 기준을 지정할 수 있다.
-- 재고 많은 순, 재고가 같다면 가격 낮은 순으로 정렬
SELECT * FROM products
ORDER BY stock_quantity DESC, price;

 


📌 LIMIT: 조회 개수 제한과 페이징

 

 

LIMIT 절은 조회 결과의 개수를 제한하기 위해 사용하며, 의미 있는 결과를 얻기 위해 ORDER BY와 함께 사용하는 것이 중요하다.

 

  • LIMIT n: 상위 n개의 결과만 가져온다.
-- 가장 비싼 상품 2개만 조회
SELECT * FROM products
ORDER BY price DESC
LIMIT 2;

 

  • LIMIT offset, row_count:
    • offset: 시작 위치 (0부터 시작) → 생략 시 0으로 간주
    • row_count: 가져올 행(row)의 개수
    • 즉, offset 개수만큼 건너뛰고, row_count 개수만큼 결과를 가져온다.
    • 이는 페이징(Pagination) 기능 구현의 핵심이다.
-- offset 공식
offset = (page_number - 1) * page_size
-- 한 페이지당 10개의 상품을 보여줄 때, 3페이지 조회
SELECT * FROM products
ORDER BY product_id
LIMIT 20, 10; -- offset = (3 - 1) * 10 = 20
  • OFFSET 키워드와 함께 사용하여 가독성을 향상시킬 수 있다.
SELECT * FROM products
ORDER BY product_id
LIMIT 10 OFFSET 20; -- 20개를 건너뛰고, 21번째부터 10개 조회

 


📌 DISTINCT: 중복 제거

 

SELECT 키워드 바로 뒤에 DISTINCT를 사용하면, 조회 결과에서 중복된 행을 제거하고 고유한 값만 남겨준다.

-- 주문한 적 있는 고객 ID 목록을 중복 없이 조회
SELECT DISTINCT customer_id FROM orders;

 


⚠️ NULL의 특별한 취급: '알 수 없는 값'

 

데이터베이스에서 NULL은 숫자 0이나 빈 문자열('')과는 완전히 다른, '알 수 없는 값' 또는 '존재하지 않는 값'을 의미하는 특별한 상태다.

 

  • 비교: NULL은 특정 값이 아니므로 등호(=)로 비교할 수 없다.
    • WHERE description = NULL과 같은 조건은 항상 '알 수 없음(UNKNOWN)'으로 판별되어 아무 결과도 반환하지 않는다.
    • 따라서 NULL 값을 찾기 위해서는 반드시 IS NULL 또는 IS NOT NULL을 사용해야 한다.
  • 정렬: MySQL에서 NULL가장 작은 값으로 취급된다.
    • 오름차순(ASC) 정렬 시 NULL 값이 가장 먼저 나온다.
    • 내림차순(DESC) 정렬 시 NULL 값이 가장 나중에 나온다.

 


🤔 NULL을 가장 큰 값으로 취급하려면?

 

SELECT 절에 IS NULL 컬럼을 추가하여, ORDER BY 절에 조건을 추가하는 트릭을 사용하면 된다.

-- description 기준으로 내림차순 정렬하되, description이 NULL인 행이 가장 먼저 나오도록 조회
SELECT
    product_id,
    name,
    description,
    description IS NULL -- NULL인 경우 1, 아닌 경우 0
FROM
    products
ORDER BY
    description IS NULL DESC, -- NULL인 경우 1이므로, 내림차순 정렬
    description DESC;