WHERE 절

WHERE 절

WHERE 절은 SELECT의 FROM 절에서 오는 데이터를 필터링할 수 있게 해줘요. WHERE 절이 있으면 그 뒤에는 UInt8 타입의 표현식이 와야 해요. 이 표현식이 0으로 평가되는 행은 이후 변환이나 결과에서 제외돼요.

출처: 문서

본문

WHERE 절은 SELECT의 FROM 절에서 오는 데이터를 필터링할 수 있게 해줘요. WHERE 절이 있으면 그 뒤에는 UInt8 타입의 표현식이 와야 해요. 이 표현식이 0으로 평가되는 행은 이후 변환 또는 결과에서 제외돼요. WHERE 절 뒤의 표현식은 comparison 및 logical operators, 또는 수많은 regular functions 중 하나와 자주 함께 사용돼요. WHERE 표현식은 기본 테이블 엔진이 지원한다면 인덱스와 파티션 프루닝(partition pruning)을 사용할 수 있는지에 따라 평가돼요.

PREWHERE

필터링을 더 효율적으로 적용하는 PREWHERE라는 필터링 최적화도 있어요. Prewhere는 필터링을 더 효율적으로 적용하기 위한 최적화예요. PREWHERE 절을 명시적으로 지정하지 않아도 기본적으로 활성화돼요.

Testing for NULL (NULL 검사)

값을 NULL인지 검사해야 한다면 다음을 사용해요.

그 외에 NULL이 포함된 표현식은 절대 통과되지 않아요.

Filtering data with logical operators (논리 연산자로 데이터 필터링)

다음 logical functions을 WHERE 절과 함께 사용하면 여러 조건을 결합할 수 있어요.

Using UInt8 columns as a condition (UInt8 열을 조건으로 사용)

ClickHouse에서 UInt8 열은 불리언 조건으로 직접 사용할 수 있어요. 여기서 0은 false, 0이 아닌 값(보통 1)은 true를 의미해요. 이에 대한 예시는 아래의 섹션에서 확인할 수 있어요.

Using comparison operators (비교 연산자 사용)

다음 comparison operators을 사용할 수 있어요.

Operator Function Description (설명) Example
a = b equals(a, b) 같음 price = 100
a == b equals(a, b) 같음 (대체 구문) price == 100
a != b notEquals(a, b) 같지 않음 category != 'Electronics'
a <> b notEquals(a, b) 같지 않음 (대체 구문) category <> 'Electronics'
a < b less(a, b) 미만 price < 200
a <= b lessOrEquals(a, b) 이하 price <= 200
a > b greater(a, b) 초과 price > 500
a >= b greaterOrEquals(a, b) 이상 price >= 500
a LIKE s like(a, b) 패턴 일치 (대소문자 구분) name LIKE '%top%'
a NOT LIKE s notLike(a, b) 패턴 불일치 (대소문자 구분) name NOT LIKE '%top%'
a ILIKE s ilike(a, b) 패턴 일치 (대소문자 무시) name ILIKE '%LAPTOP%'
a BETWEEN b AND c a >= b AND a <= c 범위 검사 (포함) price BETWEEN 100 AND 500
a NOT BETWEEN b AND c a < b OR a > c 범위 밖 검사 price NOT BETWEEN 100 AND 500

Pattern matching and conditional expressions (패턴 매칭과 조건 표현식)

비교 연산자 외에도 WHERE 절에서 패턴 매칭과 조건 표현식을 사용할 수 있어요.

Feature (기능) Syntax (구문) Case-Sensitive (대소문자 구분) Performance (성능) Best For (최적 용도)
LIKE col LIKE '%pattern%' 예 빠름 정확한 대소문자 패턴 매칭
ILIKE col ILIKE '%pattern%' 아니요 더 느림 대소문자 무시 검색
if() if(cond, a, b) 해당 없음 빠름 단순 이진 조건
multiIf() multiIf(c1, r1, c2, r2, def) 해당 없음 빠름 여러 조건
CASE CASE WHEN ... THEN ... END 해당 없음 빠름 SQL 표준 조건 로직

사용 예시는 “Pattern matching and conditional expressions”를 참고해요.

Expression with literals, columns or subqueries (리터럴, 열 또는 서브쿼리가 포함된 표현식)

WHERE 절 뒤의 표현식에는 literals, 열, 또는 조건에서 사용될 값을 반환하는 중첩 SELECT 문인 서브쿼리도 포함될 수 있어요.

Type (유형) Definition (정의) Evaluation (평가 시점) Performance (성능) Example
Literal 고정 상수 값 쿼리 작성 시점 가장 빠름 WHERE price > 100
Column 테이블 데이터 참조 행마다 빠름 WHERE price > cost
Subquery 중첩 SELECT 쿼리 실행 시점 다양함 WHERE id IN (SELECT ...)

복잡한 조건에서 리터럴, 열, 서브쿼리를 혼합할 수 있어요.

-- Literal + Column
WHERE price > 100 AND category = 'Electronics'

-- Column + Subquery
WHERE price > (SELECT AVG(price) FROM products) AND in_stock = true

-- Literal + Column + Subquery
WHERE category = 'Electronics'
  AND price < 500
  AND id IN (SELECT product_id FROM bestsellers)

-- All three with logical operators
WHERE (price > 100 OR category IN (SELECT category FROM featured))
  AND in_stock = true
  AND name LIKE '%Special%'

Examples (예제)

Testing for NULL (NULL 검사)

NULL 값이 포함된 쿼리:

CREATE TABLE t_null(x Int8, y Nullable(Int8)) ENGINE=MergeTree() ORDER BY x;
INSERT INTO t_null VALUES (1, NULL), (2, 3);

SELECT * FROM t_null WHERE y IS NULL;
SELECT * FROM t_null WHERE y != 0;
┌─x─┬────y─┐
│ 1 │ ᴺᵁᴸᴸ │
└───┴──────┘
┌─x─┬─y─┐
│ 2 │ 3 │
└───┴───┘

Filtering data with logical operators (논리 연산자로 데이터 필터링)

다음 테이블과 데이터가 있다고 가정해요.

CREATE TABLE products (
    id UInt32,
    name String,
    price Float32,
    category String,
    in_stock Bool
) ENGINE = MergeTree()
ORDER BY id;

INSERT INTO products VALUES
(1, 'Laptop', 999.99, 'Electronics', true),
(2, 'Mouse', 25.50, 'Electronics', true),
(3, 'Desk', 299.00, 'Furniture', false),
(4, 'Chair', 150.00, 'Furniture', true),
(5, 'Monitor', 350.00, 'Electronics', true),
(6, 'Lamp', 45.00, 'Furniture', false);

1. AND - 두 조건이 모두 참이어야 함:

SELECT * FROM products
WHERE category = 'Electronics' AND price < 500;
   ┌─id─┬─name────┬─price─┬─category────┬─in_stock─┐
1. │  2 │ Mouse   │  25.5 │ Electronics │ true     │
2. │  5 │ Monitor │   350 │ Electronics │ true     │
   └────┴─────────┴───────┴─────────────┴──────────┘

2. OR - 적어도 하나의 조건이 참이어야 함:

SELECT * FROM products
WHERE category = 'Furniture' OR price > 500;
   ┌─id─┬─name───┬──price─┬─category────┬─in_stock─┐
1. │  1 │ Laptop │ 999.99 │ Electronics │ true     │
2. │  3 │ Desk   │    299 │ Furniture   │ false    │
3. │  4 │ Chair  │    150 │ Furniture   │ true     │
4. │  6 │ Lamp   │     45 │ Furniture   │ false    │
   └────┴────────┴────────┴─────────────┴──────────┘

3. NOT - 조건을 부정:

SELECT * FROM products
WHERE NOT in_stock;
   ┌─id─┬─name─┬─price─┬─category──┬─in_stock─┐
1. │  3 │ Desk │   299 │ Furniture │ false    │
2. │  6 │ Lamp │    45 │ Furniture │ false    │
   └────┴──────┴───────┴───────────┴──────────┘

4. XOR - 정확히 하나의 조건만 참이어야 함(둘 다는 안 됨):

SELECT *
FROM products
WHERE xor(price > 200, category = 'Electronics')
   ┌─id─┬─name──┬─price─┬─category────┬─in_stock─┐
1. │  2 │ Mouse │  25.5 │ Electronics │ true     │
2. │  3 │ Desk  │   299 │ Furniture   │ false    │
   └────┴───────┴───────┴─────────────┴──────────┘

5. 여러 연산자 결합:

SELECT * FROM products
WHERE (category = 'Electronics' OR category = 'Furniture')
  AND in_stock = true
  AND price < 400;
   ┌─id─┬─name────┬─price─┬─category────┬─in_stock─┐
1. │  2 │ Mouse   │  25.5 │ Electronics │ true     │
2. │  4 │ Chair   │   150 │ Furniture   │ true     │
3. │  5 │ Monitor │   350 │ Electronics │ true     │
   └────┴─────────┴───────┴─────────────┴──────────┘

6. 함수 구문 사용:

SELECT * FROM products
WHERE and(or(category = 'Electronics', price > 100), in_stock);
   ┌─id─┬─name────┬──price─┬─category────┬─in_stock─┐
1. │  1 │ Laptop  │ 999.99 │ Electronics │ true     │
2. │  2 │ Mouse   │   25.5 │ Electronics │ true     │
3. │  4 │ Chair   │    150 │ Furniture   │ true     │
4. │  5 │ Monitor │    350 │ Electronics │ true     │
   └────┴─────────┴────────┴─────────────┴──────────┘

SQL 키워드 구문(AND, OR, NOT, XOR)이 일반적으로 더 읽기 쉽지만, 함수 구문은 복잡한 표현식이나 동적 쿼리를 만들 때 유용할 수 있어요.

Using UInt8 columns as a condition (UInt8 열을 조건으로 사용)

앞선 예제의 테이블을 사용하면, 열 이름을 조건으로 직접 사용할 수 있어요.

SELECT * FROM products
WHERE in_stock
   ┌─id─┬─name────┬──price─┬─category────┬─in_stock─┐
1. │  1 │ Laptop  │ 999.99 │ Electronics │ true     │
2. │  2 │ Mouse   │   25.5 │ Electronics │ true     │
3. │  4 │ Chair   │    150 │ Furniture   │ true     │
4. │  5 │ Monitor │    350 │ Electronics │ true     │
   └────┴─────────┴────────┴─────────────┴──────────┘

Using comparison operators (비교 연산자 사용)

아래 예시들은 위 예제의 테이블과 데이터를 사용해요. 간결함을 위해 결과는 생략했어요.

1. true와의 명시적 동등 비교 ( = 1 또는 = true ):

SELECT * FROM products
WHERE in_stock = true;
-- or
WHERE in_stock = 1;

2. false와의 명시적 동등 비교 ( = 0 또는 = false ):

SELECT * FROM products
WHERE in_stock = false;
-- or
WHERE in_stock = 0;

3. 부등 비교 ( != 0 또는 != false ):

SELECT * FROM products
WHERE in_stock != false;
-- or
WHERE in_stock != 0;

4. 초과:

SELECT * FROM products
WHERE in_stock > 0;

5. 이하:

SELECT * FROM products
WHERE in_stock <= 0;

6. 다른 조건과의 결합:

SELECT * FROM products
WHERE in_stock AND price < 400;

7. IN 연산자 사용: 아래 예시에서 (1, true)는 tuple이에요.

SELECT * FROM products
WHERE in_stock IN (1, true);

이를 위해 array를 사용할 수도 있어요.

SELECT * FROM products
WHERE in_stock IN [1, true];

8. 비교 스타일 혼합:

SELECT * FROM products
WHERE category = 'Electronics' AND in_stock = true;

Pattern matching and conditional expressions (패턴 매칭과 조건 표현식)

아래 예시들은 위 예제의 테이블과 데이터를 사용해요. 간결함을 위해 결과는 생략했어요.

LIKE examples (LIKE 예시)

-- Find products with 'o' in the name
SELECT * FROM products WHERE name LIKE '%o%';
-- Result: Laptop, Monitor

-- Find products starting with 'L'
SELECT * FROM products WHERE name LIKE 'L%';
-- Result: Laptop, Lamp

-- Find products with exactly 4 characters
SELECT * FROM products WHERE name LIKE '____';
-- Result: Desk, Lamp

ILIKE examples (ILIKE 예시)

-- Case-insensitive search for 'LAPTOP'
SELECT * FROM products WHERE name ILIKE '%laptop%';
-- Result: Laptop

-- Case-insensitive prefix match
SELECT * FROM products WHERE name ILIKE 'l%';
-- Result: Laptop, Lamp

IF examples (IF 예시)

-- Different price thresholds by category
SELECT * FROM products
WHERE if(category = 'Electronics', price < 500, price < 200);
-- Result: Mouse, Chair, Monitor
-- (Electronics under $500 OR Furniture under $200)

-- Filter based on stock status
SELECT * FROM products
WHERE if(in_stock, price > 100, true);
-- Result: Laptop, Chair, Monitor, Desk, Lamp
-- (In stock items over $100 OR all out-of-stock items)

multiIf examples (multiIf 예시)

-- Multiple category-based conditions
SELECT * FROM products
WHERE multiIf(
    category = 'Electronics', price < 600,
    category = 'Furniture', in_stock = true,
    false
);
-- Result: Mouse, Monitor, Chair
-- (Electronics < $600 OR in-stock Furniture)

-- Tiered filtering
SELECT * FROM products
WHERE multiIf(
    price > 500, category = 'Electronics',
    price > 100, in_stock = true,
    true
);
-- Result: Laptop, Chair, Monitor, Lamp

CASE examples (CASE 예시)

Simple CASE (단순 CASE):

-- Different rules per category
SELECT * FROM products
WHERE CASE category
    WHEN 'Electronics' THEN price < 400
    WHEN 'Furniture' THEN in_stock = true
    ELSE false
END;
-- Result: Mouse, Monitor, Chair

Searched CASE (검색 CASE):

-- Price-based tiered logic
SELECT * FROM products
WHERE CASE
    WHEN price > 500 THEN in_stock = true
    WHEN price > 100 THEN category = 'Electronics'
    ELSE true
END;
-- Result: Laptop, Monitor, Mouse, Lamp

더 알아보기 (Learn more)