Menu

SQLite WHERE 절: 조건으로 행 필터링 완벽 가이드

SQLite의 WHERE 절로 원하는 행만 골라내는 방법을 정리했습니다. 비교 연산자, AND/OR, LIKE, IN, BETWEEN, 그리고 누구나 한 번은 걸리는 NULL 함정까지 다룹니다.

이 페이지에는 실행 가능한 에디터가 있습니다 — 편집하고 실행하면 결과를 바로 볼 수 있습니다.

WHERE 절로 행을 하나씩 걸러내기

WHERE 없이 SELECT만 쓰면 테이블의 모든 행이 그대로 나옵니다. 보통은 그게 원하는 결과가 아니죠. SQLite WHERE 절을 쓰면 조건에 맞는 행만 남길 수 있습니다. SQLite가 테이블을 한 행씩 훑으면서 각 행에 대해 조건을 평가하고, 참인 행만 결과에 포함시키는 방식이에요.

세 개의 행이 반환됩니다. Neuromancer, Hyperion, 그리고 The Martian이죠. 각 행에 대해 year > 1980 조건을 검사한 뒤, 통과한 행만 결과로 남게 됩니다.

머릿속에 이런 그림을 그려두면 좋습니다. WHEREFROM과 우리가 선택한 컬럼 사이에 자리 잡은 필터예요. 조건식이 참(true)으로 평가되는 행만 이 필터를 통과합니다.

비교 연산자

기본적인 비교 연산자는 예상하는 그대로 동작합니다.

=는 같음, != 또는 <>는 "다름", 그리고 <, <=, >, >=는 크기 비교에 씁니다. 문자열 비교도 같은 연산자를 그대로 사용해서, author = 'Asimov'라고 쓰면 한 글자도 틀림없이 정확히 일치하는 값을 찾아줍니다.

한 가지 주의할 점이 있습니다. SQL에서 문자열 리터럴은 작은따옴표로 감쌉니다. 큰따옴표는 컬럼명이나 테이블명 같은 식별자(identifier)를 가리킬 때 쓰는 거예요. SQLite에서는 과거 호환성 때문에 WHERE author = "Asimov"처럼 써도 동작하긴 하지만, 다른 DB로 옮기면 깨지기 쉽고, 하필 "문자열" 값이 컬럼명과 같을 때는 조용히 엉뚱한 결과를 내기도 합니다. 그러니 문자열은 항상 작은따옴표로 쓰는 습관을 들이세요.

AND, OR 그리고 괄호로 조건 묶기

실무에서 쓰는 쿼리는 대부분 여러 조건을 한꺼번에 거는 다중 조건 쿼리입니다. AND는 양쪽 조건이 모두 참이어야 하고, OR하나라도 참이면 통과시킵니다:

첫 번째 쿼리는 최근에 나온 짧은 책 만 골라내고, 두 번째 쿼리는 두 저자 중 한 명이 쓴 책을 모두 가져옵니다.

ANDOR 를 섞어 쓸 때는 연산자 우선순위 때문에 자주 헷갈립니다. ANDOR 보다 우선순위가 높기 때문에, 다음과 같이 동작합니다:

이 식은 Herbert OR (Gibson AND year > 1980)로 해석됩니다 — 즉 연도와 상관없이 Herbert의 책 전부, 그리고 1980년 이후의 Gibson 책들이 함께 조회되죠. 의도한 결과가 아닐 가능성이 큽니다. 원하는 조건을 괄호로 명확히 묶어 주세요:

애매하면 그냥 괄호를 쳐라. 쿼리 옵티마이저는 신경도 안 쓰고, 나중에 코드를 읽는 사람은 분명 고마워할 것이다.

NULL은 일반 값처럼 동작하지 않는다

이건 SQLite WHERE 절을 쓰다 보면 누구나 한 번씩은 걸려 넘어지는 함정이다. SQL에서 NULL은 "알 수 없음"을 뜻하고, 알 수 없는 값끼리는 비교 자체가 성립하지 않는다. column = NULL거짓 이 아니라 결과가 NULL이며, WHERE는 이걸 "이 행은 건너뛰기"로 처리해 버린다.

IS NULLIS NOT NULL만이 NULL을 직접 검사할 수 있는 연산자입니다. 이건 손에 익혀두세요 — NULL을 다른 연산자로 비교하면 결과가 무조건 NULL이 되고, 해당 행은 조용히 빠져버립니다.

부정 연산도 마찬가지입니다. WHERE author != 'Asimov'author IS NULL인 행을 포함하지 않습니다. NULL != 'Asimov' 역시 NULL이기 때문이죠. NULL까지 같이 가져오고 싶다면 명시적으로 적어줘야 합니다: WHERE author != 'Asimov' OR author IS NULL.

IN과 BETWEEN: 매일 쓰게 되는 단축 문법

IN 연산자는 값이 특정 목록 안에 있는지 확인합니다. OR를 줄줄이 늘어놓는 대신 깔끔하게 쓸 수 있죠:

BETWEEN은 양쪽 끝값을 포함 하는 범위 조건을 검사합니다:

year BETWEEN 1980 AND 2000year >= 1980 AND year <= 2000과 완전히 동일합니다. 그저 더 짧을 뿐이죠. 한 가지 기억할 점은 양쪽 경계값이 모두 포함된다는 것입니다. 경계값을 제외하고 싶다면 비교 연산자로 직접 풀어 써야 합니다.

INNULL에 관해 짚고 넘어갈 것이 하나 있습니다. WHERE column NOT IN (1, 2, NULL)이라고 쓰면 어떤 행도 절대 반환되지 않습니다. NULL과의 비교 결과는 항상 NULL이기 때문이죠. 리스트에서 NULL을 빼거나, IS NULL로 따로 처리해 주세요.

LIKE로 패턴 매칭하기

SQLite LIKE 사용법은 간단합니다. 두 가지 와일드카드로 문자열 패턴을 매칭합니다.

  • %는 임의의 문자열과 매칭됩니다(빈 문자열 포함).
  • _는 정확히 한 글자와 매칭됩니다.

기본적으로 SQLite의 LIKE는 ASCII 문자에 대해 대소문자를 구분하지 않습니다. 즉 'Dune' LIKE 'dune'이 참으로 평가됩니다. Postgres를 쓰다가 넘어온 분이라면 좀 의외일 수 있는데, Postgres에서는 LIKE가 대소문자를 구분하고 대소문자를 무시하려면 ILIKE를 따로 써야 하기 때문이죠. (참고로 SQLite에는 ILIKE가 없습니다.)

대소문자를 구분해서 매칭해야 한다면 두 가지 방법이 있습니다. 먼저 전역 pragma를 켜는 방식입니다.

PRAGMA case_sensitive_like = ON;

또는 항상 대소문자를 구분하고 유닉스 스타일 와일드카드(*는 임의의 문자열, ?는 한 글자)를 사용하는 GLOB을 활용할 수도 있습니다.

GLOB 'd*'로 검색하면 아무것도 걸리지 않습니다 — 대소문자를 구분하기 때문이죠.

날짜로 필터링하기

SQLite는 날짜를 텍스트(보통 YYYY-MM-DD 또는 ISO 8601 전체 형식)로 저장합니다. 그래서 ISO 형식만 지킨다면 문자열 비교가 곧 날짜 비교로도 자연스럽게 동작합니다:

'2024-06-01' < '2024-11-08'은 문자열로 비교해도, 날짜로 비교해도 똑같이 참이기 때문에 위 쿼리들이 기대한 대로 동작합니다. 그런데 만약 날짜를 다른 형식('15/01/2024', 'Jan 15 2024' 같은)으로 저장하면, 비교 결과가 조용히 틀려버립니다. 그러니 항상 ISO 8601 형식을 쓰세요. 나중에 본인이 고마워합니다.

좀 더 까다로운 날짜 연산(연도만 뽑아내거나, "오늘"과 비교한다거나)이 필요하다면 SQLite에는 date(), strftime(), julianday() 같은 함수가 준비되어 있습니다. 자세한 내용은 날짜·시간 챕터에서 다루겠습니다.

여러 조건을 한 번에 조합하기

지금까지 배운 것들을 한꺼번에 쓰는 쿼리는 다음과 같습니다:

한 줄씩 읽어 보면 이렇습니다. 연도가 있는 행만 남기고, 범위 안에 들어와야 하며, 두 저자 중 하나거나 또는 분량이 충분히 길어야 하고, 초안은 제외합니다. 이게 바로 WHERE 절이 가장 잘하는 일이죠. 작고 읽기 쉬운 조건들을 엮어서 정밀한 필터를 만들어 내는 것.

습관으로 들여 두면 좋은 두 가지가 있습니다.

  • 조건마다 줄을 바꿔 들여쓰기. WHERE 절이 길어지면 한 줄에 다 몰아 쓸 때 금방 알아보기 힘들어집니다.
  • 의도가 한눈에 안 들어오는 조건에는 이 조건이 있는지 주석을 달기. -- 초안 제외 같은 한 줄이 나중에 큰 도움이 됩니다.

다음 단계: 연산자와 NULL 자세히 살펴보기

WHERE 절은 결국 컬럼에 연산자를 적용하는 일이고, 거기서 NULL은 모든 연산자의 동작을 조용히 바꿔 놓습니다. 다음 글에서는 SQLite의 연산자들을 더 깊이 다뤄 봅니다. 산술 연산, ||를 이용한 문자열 연결, IS 계열, 그리고 3값 논리(three-valued logic)까지 살펴보면, 더 이상 예상치 못한 동작에 당황할 일이 없을 겁니다.

자주 묻는 질문

SQLite에서 WHERE 절은 어떻게 동작하나요?

WHERE는 각 행에 대해 조건을 평가해서 참인 행만 결과에 남기고, 거짓이거나 NULL인 행은 버립니다. 위치는 FROM 바로 뒤예요. 형식은 SELECT ... FROM table WHERE condition 입니다.

WHERE 절에서 여러 조건을 어떻게 묶나요?

ANDOR를 씁니다. AND는 양쪽이 모두 참이어야 하고, OR는 한쪽만 참이면 됩니다. 우선순위는 ANDOR보다 높기 때문에, 두 가지를 섞어서 쓸 때는 괄호로 명확하게 묶어주는 게 안전해요. 예: WHERE (a OR b) AND c.

WHERE column = NULL은 왜 안 되나요?

NULL은 "알 수 없음"이라는 의미라서, =!=로 비교하면 결과가 참도 거짓도 아닌 NULL이 나옵니다. WHERE는 조건이 참일 때만 행을 남기니까 결국 아무것도 안 걸리는 거죠. NULL을 검사할 때는 반드시 IS NULL, IS NOT NULL을 써야 합니다.

SQLite의 LIKE는 대소문자를 구분하나요?

기본적으로 ASCII 문자에 대해서는 대소문자를 구분하지 않습니다. 즉 'Hello' LIKE 'hello'는 참이에요. 대소문자를 구분하고 싶다면 PRAGMA case_sensitive_like = ON;을 설정하거나, 아예 GLOB을 쓰면 됩니다. GLOB은 항상 대소문자를 구분하고 유닉스 스타일 와일드카드(*, ?)를 사용해요.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기