이미지 로딩 중...

SQL 논리 연산자와 복합 조건 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 11. 22. · 2 Views

SQL 논리 연산자와 복합 조건 완벽 가이드

데이터베이스 쿼리 작성 시 필수적인 AND, OR, NOT 연산자를 마스터하고, 복잡한 조건을 우아하게 다루는 방법을 배워봅니다. 실무에서 자주 만나는 복합 조건 쿼리를 효과적으로 작성하는 노하우를 초급자 눈높이에서 친절하게 알려드립니다.


목차

  1. AND 연산자로 여러 조건 결합
  2. OR 연산자로 선택적 조건
  3. NOT 연산자로 부정 조건
  4. 연산자 우선순위 이해하기
  5. 괄호로 조건 그룹화
  6. 실전 복합 쿼리 작성

1. AND 연산자로 여러 조건 결합

시작하며

여러분이 쇼핑몰 데이터베이스에서 "가격이 10만원 이하이면서 동시에 재고가 있는 상품"을 찾아야 하는 상황을 떠올려보세요. 한 가지 조건만으로는 원하는 결과를 얻을 수 없죠.

실무에서는 이렇게 여러 조건을 동시에 만족해야 하는 경우가 정말 많습니다. 회원 중에서 "20대이면서 서울에 사는 사람", 주문 중에서 "결제 완료되었고 배송 시작 전인 건" 등 두 가지 이상의 조건을 모두 충족해야 하는 데이터를 찾는 일은 개발자의 일상입니다.

바로 이럴 때 필요한 것이 AND 연산자입니다. 마치 "그리고"라는 말처럼, 여러 조건을 하나로 묶어서 "이것도 맞고 저것도 맞는" 데이터만 정확하게 찾아낼 수 있게 해줍니다.

개요

간단히 말해서, AND 연산자는 여러 조건을 연결하여 "모든 조건이 동시에 참(TRUE)일 때만" 데이터를 가져오는 논리 연산자입니다. 실무에서 이 연산자가 필요한 이유는 단순합니다.

비즈니스 요구사항은 대부분 복합적이기 때문이죠. "VIP 고객 중에서 최근 3개월 이내 구매한 사람에게 쿠폰 발송"처럼 여러 기준을 동시에 만족하는 대상을 찾아야 하는 경우가 훨씬 많습니다.

기존에 조건 하나만으로 데이터를 필터링했다면, 이제는 AND를 사용해서 여러 필터를 동시에 적용할 수 있습니다. 이는 마치 체에 여러 단계의 필터를 겹쳐 놓는 것과 같아요.

AND 연산자의 핵심 특징은 세 가지입니다. 첫째, 모든 조건이 참이어야만 결과에 포함됩니다.

둘째, 조건의 순서는 결과에 영향을 주지 않습니다. 셋째, 필요한 만큼 여러 개의 AND를 연결할 수 있습니다.

이러한 특징들 덕분에 복잡한 비즈니스 로직을 명확하고 정확하게 쿼리로 표현할 수 있습니다.

코드 예제

-- 상품 테이블에서 가격이 100,000원 이하이면서 재고가 10개 이상인 상품 조회
SELECT product_name, price, stock_quantity
FROM products
WHERE price <= 100000
  AND stock_quantity >= 10;

-- 회원 테이블에서 20대이면서 서울에 거주하는 활성 회원 찾기
SELECT user_name, age, city, status
FROM users
WHERE age BETWEEN 20 AND 29
  AND city = '서울'
  AND status = 'active';

설명

이것이 하는 일: AND 연산자는 WHERE 절에서 여러 조건식을 연결하여, 모든 조건이 동시에 만족될 때만 해당 행(row)을 결과에 포함시킵니다. 첫 번째 예제를 살펴보면, price <= 100000stock_quantity >= 10 두 조건이 AND로 연결되어 있습니다.

데이터베이스는 먼저 각 상품의 가격을 확인하고, 10만원 이하인 상품을 1차로 선별합니다. 그런 다음 이렇게 선별된 상품 중에서 다시 재고가 10개 이상인 것만 최종 선택합니다.

두 조건을 모두 통과한 상품만 결과로 나오는 것이죠. 두 번째 예제는 더 복잡합니다.

세 개의 조건이 AND로 연결되어 있는데, age BETWEEN 20 AND 29로 20대를 필터링하고, city = '서울'로 거주지를 확인하며, status = 'active'로 활성 회원 여부까지 체크합니다. 이 세 가지 조건을 모두 만족하는 회원만 최종 결과에 나타납니다.

내부적으로 AND 연산은 Boolean 논리를 따릅니다. TRUE AND TRUE는 TRUE이지만, TRUE AND FALSE는 FALSE가 됩니다.

따라서 조건 중 하나라도 거짓이면 그 행은 결과에서 제외됩니다. 이는 매우 엄격한 필터링이지만, 정확한 데이터를 얻는 데 필수적입니다.

여러분이 이 연산자를 사용하면 복잡한 비즈니스 요구사항을 정확하게 구현할 수 있습니다. 불필요한 데이터를 철저히 걸러내어 쿼리 성능을 높이고, 애플리케이션 단에서 추가 필터링할 필요를 줄여 전체 시스템 효율을 개선할 수 있습니다.

또한 SQL 자체가 비즈니스 로직을 명확하게 표현하므로 코드 가독성과 유지보수성도 향상됩니다.

실전 팁

💡 인덱스가 있는 컬럼을 AND 조건의 앞쪽에 배치하면 쿼리 성능이 향상됩니다. 데이터베이스가 먼저 인덱스를 활용해 데이터를 빠르게 좁힐 수 있기 때문입니다.

💡 NULL 값 처리에 주의하세요. column AND other_column 형태에서 한 컬럼이 NULL이면 예상과 다른 결과가 나올 수 있습니다. NULL 체크는 IS NULL 또는 IS NOT NULL을 명시적으로 사용하세요.

💡 AND 조건이 많아질수록 결과가 줄어듭니다. 조건을 5개, 10개 연결하면 조건을 만족하는 데이터가 거의 없을 수 있으니, 실무에서는 꼭 필요한 조건만 사용하세요.

💡 디버깅 시 조건을 하나씩 제거해가며 테스트하면 문제를 빠르게 찾을 수 있습니다. 예상보다 결과가 적다면 어느 조건이 너무 엄격한지 확인해보세요.


2. OR 연산자로 선택적 조건

시작하며

여러분이 고객센터에서 "서울 또는 경기도에 사는 회원"에게 지역 이벤트 공지를 보내야 한다고 상상해보세요. 서울 회원만 찾고, 경기도 회원만 따로 찾아서 합치는 건 너무 번거롭죠.

실무에서는 이렇게 "이것 아니면 저것"이라는 선택적 조건이 정말 자주 등장합니다. "결제 방법이 카드 또는 계좌이체인 주문", "상태가 배송중 또는 배송완료인 건" 등 여러 가지 중 하나만 만족하면 되는 경우가 많습니다.

바로 이럴 때 필요한 것이 OR 연산자입니다. "또는"이라는 의미처럼, 여러 조건 중 적어도 하나만 맞으면 데이터를 가져올 수 있게 해주는 강력한 도구입니다.

개요

간단히 말해서, OR 연산자는 여러 조건을 연결하여 "조건 중 하나라도 참(TRUE)이면" 데이터를 가져오는 논리 연산자입니다. 실무에서 OR이 필요한 이유는 비즈니스 요구사항이 종종 "복수 선택"을 요구하기 때문입니다.

예를 들어, "프리미엄 회원이거나 누적 구매액이 100만원 이상인 고객에게 특별 할인"처럼 여러 기준 중 하나만 충족해도 대상이 되는 경우가 많습니다. 기존에 AND로만 조건을 연결했다면 범위가 너무 좁아져서 결과가 거의 없을 수 있습니다.

하지만 OR을 사용하면 선택의 폭을 넓혀서 더 많은 대상을 포함할 수 있죠. 이는 마치 여러 개의 입구 중 하나만 통과해도 들어갈 수 있는 것과 같습니다.

OR 연산자의 핵심 특징은 세 가지입니다. 첫째, 조건 중 하나만 참이어도 결과에 포함됩니다.

둘째, AND보다 결과 범위가 넓습니다. 셋째, IN 연산자로 간단히 표현할 수 있는 경우도 많습니다.

이러한 특징 덕분에 유연한 데이터 조회가 가능하고, 복잡한 비즈니스 로직을 자연스럽게 표현할 수 있습니다.

코드 예제

-- 서울 또는 경기에 거주하는 회원 찾기
SELECT user_name, city
FROM users
WHERE city = '서울'
   OR city = '경기';

-- 상태가 '배송중' 또는 '배송완료'인 주문 조회
SELECT order_id, status, delivery_date
FROM orders
WHERE status = '배송중'
   OR status = '배송완료';

-- 프리미엄 회원이거나 누적 구매액이 1,000,000원 이상인 고객
SELECT customer_name, membership_type, total_purchase
FROM customers
WHERE membership_type = 'PREMIUM'
   OR total_purchase >= 1000000;

설명

이것이 하는 일: OR 연산자는 WHERE 절에서 여러 조건을 연결하여, 조건 중 최소 하나만 만족되어도 해당 행을 결과에 포함시킵니다. 첫 번째 예제를 보면, city = '서울'city = '경기' 두 조건이 OR로 연결되어 있습니다.

데이터베이스는 각 회원의 city 컬럼을 확인하면서, 서울인 회원도 선택하고 경기인 회원도 선택합니다. 둘 중 하나만 맞으면 되니까 두 지역 모두의 회원이 결과에 나타나게 됩니다.

두 번째 예제에서는 주문 상태를 체크하는데, '배송중' 또는 '배송완료' 중 하나만 맞아도 결과에 포함됩니다. 이렇게 하면 배송과 관련된 모든 주문을 한 번에 조회할 수 있어서 편리합니다.

참고로 이런 경우는 status IN ('배송중', '배송완료')로도 표현할 수 있는데, 가독성이 더 좋습니다. 세 번째 예제는 더 실무적입니다.

회원 등급이 프리미엄이거나, 또는 누적 구매액이 100만원 이상이면 특별 고객으로 분류됩니다. 이렇게 서로 다른 타입의 조건(문자열 비교와 숫자 비교)도 OR로 자유롭게 연결할 수 있습니다.

내부적으로 OR 연산은 TRUE OR FALSE = TRUE, FALSE OR TRUE = TRUE, TRUE OR TRUE = TRUE가 되며, 오직 FALSE OR FALSE만 FALSE가 됩니다. 따라서 조건 중 하나라도 참이면 그 행은 결과에 포함되는 것이죠.

여러분이 OR을 사용하면 유연한 검색 기능을 구현할 수 있습니다. 사용자가 여러 필터 옵션 중 일부만 선택했을 때도 자연스럽게 처리할 수 있고, 비즈니스 요구사항의 "포괄성"을 코드로 정확히 표현할 수 있습니다.

다만 조건이 많아지면 결과가 너무 많아질 수 있으니 적절한 균형을 유지해야 합니다.

실전 팁

💡 같은 컬럼에 대한 여러 OR 조건은 IN 연산자로 바꾸면 훨씬 깔끔합니다. city IN ('서울', '경기', '인천')처럼 작성하면 가독성이 좋아집니다.

💡 OR 조건이 많으면 쿼리 성능이 저하될 수 있습니다. 인덱스를 효과적으로 활용하기 어렵기 때문인데, 가능하면 조건을 3-4개 이내로 유지하세요.

💡 OR와 AND를 함께 쓸 때는 반드시 괄호로 그룹화하세요. WHERE a = 1 OR b = 2 AND c = 3은 의도와 다르게 동작할 수 있습니다.

💡 전체 테이블 스캔을 유발할 수 있으니, 가능하면 각 OR 조건에 인덱스가 있는 컬럼을 사용하세요. 성능 차이가 수십 배까지 날 수 있습니다.

💡 디버깅할 때는 각 OR 조건을 개별적으로 실행해보세요. 어느 조건이 얼마나 많은 데이터를 가져오는지 파악하면 성능 튜닝에 도움이 됩니다.


3. NOT 연산자로 부정 조건

시작하며

여러분이 이벤트 대상자를 선정하는데 "탈퇴하지 않은 회원"을 찾아야 한다고 생각해보세요. 탈퇴한 회원을 제외하고 싶은데, 일일이 활성/휴면/정지 상태를 나열하기엔 너무 복잡하죠.

실무에서는 이렇게 "~가 아닌" 조건이 필요한 경우가 생각보다 많습니다. "재고가 없지 않은 상품", "결제 실패가 아닌 주문", "스팸이 아닌 메시지" 등 특정 상태를 제외하고 나머지 모두를 포함하고 싶을 때가 자주 있습니다.

바로 이럴 때 필요한 것이 NOT 연산자입니다. "~이 아닌"이라는 부정의 의미로, 조건을 반대로 뒤집어서 원하지 않는 데이터를 깔끔하게 제외할 수 있게 해줍니다.

개요

간단히 말해서, NOT 연산자는 조건의 참/거짓을 반대로 뒤집어서, 조건이 거짓(FALSE)일 때 데이터를 가져오는 논리 연산자입니다. 실무에서 NOT이 필요한 이유는 "제외 로직"이 "포함 로직"보다 간단할 때가 많기 때문입니다.

예를 들어, 10가지 회원 상태 중 "탈퇴" 하나만 제외하고 싶다면, 9가지를 나열하는 것보다 "탈퇴가 아닌"으로 표현하는 게 훨씬 명확하고 유지보수하기 좋습니다. 기존에 긍정 조건만 사용했다면, 복잡한 상황에서 코드가 지저분해지고 실수할 여지가 많았을 겁니다.

하지만 NOT을 사용하면 조건을 간결하게 유지하면서도 정확한 의도를 표현할 수 있습니다. NOT 연산자의 핵심 특징은 세 가지입니다.

첫째, 조건의 결과를 완전히 반대로 바꿉니다. 둘째, !=, <>, NOT IN, NOT EXISTS 등 다양한 형태로 사용됩니다.

셋째, 가독성을 위해 상황에 따라 긍정문으로 바꿔 쓸 수도 있습니다. 이러한 특징 덕분에 복잡한 제외 로직을 명확하게 표현하고, 코드의 의도를 더 직관적으로 전달할 수 있습니다.

코드 예제

-- 탈퇴하지 않은 회원 조회
SELECT user_name, status
FROM users
WHERE status != '탈퇴';
-- 또는 WHERE NOT status = '탈퇴';

-- 서울에 거주하지 않는 회원 찾기
SELECT user_name, city
FROM users
WHERE city <> '서울';

-- 특정 카테고리에 속하지 않는 상품 조회
SELECT product_name, category
FROM products
WHERE category NOT IN ('의류', '식품', '전자기기');

-- 재고가 0이 아닌 상품 (재고가 있는 상품)
SELECT product_name, stock_quantity
FROM products
WHERE NOT stock_quantity = 0;
-- 또는 WHERE stock_quantity != 0;

설명

이것이 하는 일: NOT 연산자는 조건식의 Boolean 결과를 반대로 뒤집어서, 원래 조건이 거짓인 행만 결과에 포함시킵니다. 첫 번째 예제를 보면, status != '탈퇴'는 상태가 탈퇴가 "아닌" 모든 회원을 선택합니다.

!= 기호는 "같지 않다"를 의미하는 NOT의 한 형태입니다. 같은 의미로 NOT status = '탈퇴'처럼 명시적으로 NOT 키워드를 쓸 수도 있는데, 어느 쪽이든 결과는 동일합니다.

두 번째 예제의 <> 연산자는 != 와 완전히 같은 의미로, SQL 표준에서 "같지 않다"를 나타냅니다. 서울이 아닌 모든 지역의 회원이 선택되는데, 이렇게 하면 경기, 부산, 대구 등 서울 외 모든 도시를 일일이 나열할 필요가 없어 편리합니다.

세 번째 예제의 NOT IN은 매우 강력합니다. 괄호 안의 목록에 포함되지 않는 모든 값을 선택하는데, 여기서는 의류, 식품, 전자기기가 아닌 다른 모든 카테고리의 상품을 가져옵니다.

이는 category != '의류' AND category != '식품' AND category != '전자기기'와 같은 의미지만 훨씬 간결합니다. 네 번째 예제는 재고가 0이 아닌, 즉 재고가 있는 상품을 찾습니다.

NOT stock_quantity = 0 또는 stock_quantity != 0 둘 다 가능하지만, 후자가 좀 더 직관적입니다. 실무에서는 가독성을 고려해 상황에 맞게 선택하세요.

여러분이 NOT을 사용하면 제외 로직을 명확하게 표현할 수 있고, 코드 길이를 대폭 줄일 수 있습니다. 특히 제외해야 할 항목이 포함해야 할 항목보다 적을 때 진가를 발휘합니다.

또한 비즈니스 요구사항이 "~을 제외하고"라고 표현될 때, 그 의도를 SQL로 직역할 수 있어 커뮤니케이션 오류를 줄일 수 있습니다.

실전 팁

💡 NULL 값 처리에 주의하세요. column != 'value' 조건은 NULL 값을 제외합니다. NULL도 포함하려면 (column != 'value' OR column IS NULL)처럼 명시해야 합니다.

💡 가독성을 위해 긍정문으로 바꿔 쓸 수 있는지 고려하세요. NOT stock = 0보다 stock > 0이 더 이해하기 쉬울 수 있습니다.

💡 NOT IN은 대량 데이터에서 성능이 떨어질 수 있습니다. 목록이 길다면 LEFT JOIN과 IS NULL을 활용한 안티 조인 패턴을 고려하세요.

💡 이중 부정은 피하세요. NOT (NOT condition)은 헷갈리고 실수를 유발합니다. 조건을 단순하게 유지하는 게 중요합니다.

💡 NOT EXISTS는 서브쿼리에서 매우 유용합니다. "주문한 적 없는 고객"처럼 관계 테이블에 데이터가 없는 경우를 찾을 때 강력합니다.


4. 연산자 우선순위 이해하기

시작하며

여러분이 수학 시간에 배운 "곱셈과 나눗셈을 덧셈과 뺄셈보다 먼저 계산한다"는 규칙을 기억하시나요? SQL에도 똑같은 우선순위 규칙이 있습니다.

그런데 이걸 모르면 큰일납니다. 실무에서 이런 일이 실제로 벌어집니다.

"서울에 사는 20대 또는 30대"를 찾으려다가 "서울에 사는 20대, 또는 (지역 상관없이) 모든 30대"를 찾아버리는 실수 말이죠. AND와 OR을 섞어 쓸 때 우선순위를 모르면 전혀 다른 결과가 나옵니다.

바로 이럴 때 연산자 우선순위를 정확히 이해해야 합니다. SQL이 여러분의 조건을 어떤 순서로 평가하는지 알아야 의도한 대로 쿼리가 작동하고, 버그를 예방할 수 있습니다.

개요

간단히 말해서, 연산자 우선순위는 SQL이 여러 조건을 평가할 때 "어떤 연산자를 먼저 처리하는지"를 정하는 규칙입니다. 수학의 사칙연산 우선순위와 같은 개념입니다.

SQL에서 기본 우선순위는 이렇습니다: NOT이 가장 먼저, 그 다음 AND, 마지막으로 OR. 이 순서를 모르면 a OR b AND c(a OR b) AND c인지 a OR (b AND c)인지 헷갈려서 버그가 발생합니다.

정답은 후자입니다. AND가 먼저 평가되거든요.

기존에 조건을 직관적으로만 작성했다면, 복잡한 쿼리에서 예상 밖의 결과를 만날 수 있습니다. 하지만 우선순위를 정확히 알고 괄호를 적절히 사용하면, 어떤 복잡한 조건이든 명확하게 제어할 수 있습니다.

우선순위 규칙의 핵심 포인트는 세 가지입니다. 첫째, NOT > AND > OR 순서로 평가됩니다.

둘째, 같은 우선순위는 왼쪽에서 오른쪽으로 평가됩니다. 셋째, 괄호를 사용하면 우선순위를 강제로 바꿀 수 있습니다.

이러한 규칙을 마스터하면 복잡한 비즈니스 로직을 정확히 SQL로 번역할 수 있고, 팀원들과의 코드 리뷰에서도 명확하게 소통할 수 있습니다.

코드 예제

-- 잘못된 예: 의도와 다르게 동작할 수 있음
SELECT * FROM users
WHERE city = '서울' OR city = '경기' AND age >= 20;
-- 실제로는 (city = '서울') OR (city = '경기' AND age >= 20)로 평가됨
-- 서울 사는 모든 사람 + 경기 사는 20세 이상

-- 올바른 예: 괄호로 의도를 명확히
SELECT * FROM users
WHERE (city = '서울' OR city = '경기') AND age >= 20;
-- 서울이나 경기에 살면서 20세 이상인 사람

-- NOT의 우선순위
SELECT * FROM products
WHERE NOT category = '의류' AND price < 50000;
-- NOT이 먼저: (NOT category = '의류') AND (price < 50000)
-- 의류가 아니면서 5만원 미만

설명

이것이 하는 일: SQL 엔진은 여러 논리 연산자가 섞여 있을 때, 정해진 우선순위에 따라 조건을 단계적으로 평가하여 최종 참/거짓을 판단합니다. 첫 번째 예제의 문제점을 자세히 살펴봅시다.

city = '서울' OR city = '경기' AND age >= 20은 AND가 OR보다 우선순위가 높아서 먼저 평가됩니다. 따라서 SQL 엔진은 이를 city = '서울' OR (city = '경기' AND age >= 20)로 해석합니다.

결과적으로 서울에 사는 사람은 나이와 무관하게 모두 선택되고, 경기에 사는 사람은 20세 이상만 선택됩니다. 의도가 "서울이나 경기에 사는 20세 이상"이었다면 완전히 다른 결과죠.

두 번째 예제가 올바른 방법입니다. 괄호로 (city = '서울' OR city = '경기')를 먼저 그룹화하면, 이 부분이 먼저 평가됩니다.

서울이거나 경기인 사람들이 1차로 선별되고, 그 다음 AND age >= 20이 적용되어 20세 이상만 최종 선택됩니다. 이제 의도한 대로 정확히 동작합니다.

세 번째 예제는 NOT의 높은 우선순위를 보여줍니다. NOT category = '의류' AND price < 50000에서 NOT이 가장 먼저 평가되어 (NOT category = '의류')가 처리되고, 그 다음 AND로 가격 조건이 결합됩니다.

만약 NOT (category = '의류' AND price < 50000)를 의도했다면 괄호를 반드시 써야 합니다. 실전에서 우선순위를 암기하는 것보다 중요한 건, 복잡한 조건에서는 무조건 괄호를 사용하는 습관입니다.

괄호는 성능에 영향을 주지 않으면서 가독성과 정확성을 동시에 높여줍니다. 여러분이 우선순위를 제대로 이해하면 쿼리 버그의 80%를 예방할 수 있습니다.

특히 AND와 OR을 섞어 쓰는 복잡한 조건에서 의도를 명확히 표현할 수 있고, 나중에 코드를 다시 볼 때도 헷갈리지 않습니다. 코드 리뷰에서도 "이 쿼리 의도가 뭐죠?"라는 질문을 받지 않게 됩니다.

실전 팁

💡 복잡한 조건에서는 우선순위를 외우기보다 항상 괄호를 사용하세요. 코드 가독성이 높아지고 실수를 방지할 수 있습니다.

💡 AND와 OR이 섞인 조건은 팀원이 봤을 때도 헷갈릴 수 있습니다. 괄호로 명확히 하면 커뮤니케이션 비용이 줄어듭니다.

💡 쿼리 결과가 이상하다면 먼저 우선순위를 의심하세요. EXPLAIN이나 쿼리 플랜보다 조건 자체를 먼저 점검하는 게 빠릅니다.

💡 NOT을 AND/OR과 함께 쓸 때는 특히 조심하세요. NOT a AND bNOT (a AND b)는 완전히 다른 의미입니다.

💡 개발 초기에는 조건을 여러 줄로 나눠 쓰면 가독성이 좋습니다. 괄호와 들여쓰기를 활용해 구조를 명확히 보이게 하세요.


5. 괄호로 조건 그룹화

시작하며

여러분이 복잡한 수식을 계산할 때 괄호로 묶어서 순서를 명확히 하는 것처럼, SQL에서도 괄호는 조건의 의미를 명확하게 만드는 강력한 도구입니다. 실무에서 비즈니스 요구사항은 점점 복잡해집니다.

"VIP 회원이거나 최근 3개월 내 구매한 고객 중에서, 서울이나 경기에 거주하면서 이메일 수신 동의한 사람"처럼 여러 단계의 조건이 중첩되는 경우가 흔합니다. 이럴 때 괄호 없이는 의도를 정확히 표현할 수 없습니다.

바로 이럴 때 필요한 것이 괄호를 활용한 조건 그룹화입니다. 조건들을 논리적인 단위로 묶어서, SQL 엔진과 사람 모두에게 명확한 의도를 전달할 수 있게 해줍니다.

개요

간단히 말해서, 괄호는 여러 조건을 논리적인 단위로 묶어서 평가 순서를 명시적으로 제어하고, 복잡한 조건의 가독성을 높이는 SQL의 핵심 문법입니다. 실무에서 괄호가 필수인 이유는 비즈니스 로직이 계층적 구조를 갖기 때문입니다.

"A이면서 (B 또는 C)"처럼 조건 안에 조건이 들어가는 구조를 표현하려면 괄호 없이는 불가능합니다. 괄호는 단순한 문법이 아니라 논리적 사고를 코드로 번역하는 도구입니다.

기존에 단순한 AND나 OR만 사용했다면, 복잡한 요구사항을 여러 쿼리로 쪼개거나 애플리케이션 코드에서 추가 필터링을 해야 했을 겁니다. 하지만 괄호를 제대로 활용하면 하나의 쿼리로 복잡한 로직을 정확하게 표현할 수 있습니다.

괄호 사용의 핵심 원칙은 세 가지입니다. 첫째, 논리적으로 함께 평가되어야 할 조건을 묶습니다.

둘째, AND와 OR이 섞여 있으면 반드시 괄호로 의도를 명확히 합니다. 셋째, 중첩 괄호도 필요하다면 두려워하지 말고 사용합니다.

이러한 원칙을 지키면 쿼리의 정확성과 유지보수성이 동시에 향상됩니다.

코드 예제

-- 복잡한 회원 타겟팅: VIP이거나 최근 구매자 중, 수도권 거주자
SELECT user_name, membership, last_purchase_date, city
FROM users
WHERE (membership = 'VIP' OR last_purchase_date >= DATE_SUB(NOW(), INTERVAL 3 MONTH))
  AND (city = '서울' OR city = '경기' OR city = '인천');

-- 상품 필터링: 저가 또는 할인 중이면서, 재고가 있는 경우
SELECT product_name, price, discount_rate, stock
FROM products
WHERE (price < 50000 OR discount_rate > 0)
  AND stock > 0;

-- 주문 검색: 결제 완료되었거나 배송중이면서, 특정 지역이 아닌 경우
SELECT order_id, status, delivery_area
FROM orders
WHERE (status = '결제완료' OR status = '배송중')
  AND NOT (delivery_area = '제주' OR delivery_area = '울릉');

-- 중첩 괄호: 복잡한 고객 세그먼트
SELECT customer_name, age, city, purchase_count
FROM customers
WHERE ((age BETWEEN 20 AND 30 AND city = '서울')
       OR (age BETWEEN 40 AND 50 AND city = '부산'))
  AND purchase_count >= 5;

설명

이것이 하는 일: 괄호는 조건식의 일부를 하나의 단위로 묶어서 먼저 평가하게 만들고, 그 결과를 다른 조건과 결합합니다. 마치 수학 공식에서 괄호 안을 먼저 계산하는 것과 같습니다.

첫 번째 예제를 분석해봅시다. 첫 번째 괄호 (membership = 'VIP' OR last_purchase_date >= ...)는 "VIP 회원이거나 최근 3개월 내 구매자"를 선별합니다.

두 번째 괄호 (city = '서울' OR city = '경기' OR city = '인천')는 수도권 거주자를 선별합니다. 이 두 그룹이 AND로 연결되어, 둘 다 만족하는 사람만 최종 선택됩니다.

괄호가 없었다면 OR과 AND의 우선순위 때문에 전혀 다른 결과가 나왔을 겁니다. 두 번째 예제는 더 직관적입니다.

첫 번째 괄호에서 "저가이거나 할인 중인" 상품을 먼저 필터링하고, 그 중에서 재고가 있는 것만 선택합니다. 만약 괄호 없이 price < 50000 OR discount_rate > 0 AND stock > 0으로 썼다면, AND가 먼저 평가되어 "저가 상품 전체 + (할인 중이면서 재고 있는 상품)"이 선택됩니다.

의도와 완전히 다르죠. 세 번째 예제는 NOT과 괄호의 조합입니다.

NOT (delivery_area = '제주' OR delivery_area = '울릉')는 제주나 울릉이 아닌 지역을 의미합니다. 괄호가 없으면 NOT이 첫 번째 조건에만 적용되어 버그가 발생합니다.

네 번째 예제는 중첩 괄호의 강력함을 보여줍니다. 안쪽 괄호들이 각각 "서울 거주 20-30대"와 "부산 거주 40-50대"를 선별하고, 이들을 OR로 합친 후, 다시 구매 횟수 조건과 AND로 결합합니다.

복잡하지만 괄호 덕분에 의도가 명확합니다. 여러분이 괄호를 능숙하게 사용하면 어떤 복잡한 비즈니스 로직도 하나의 쿼리로 정확히 표현할 수 있습니다.

데이터베이스에서 최대한 필터링하면 애플리케이션 코드가 간결해지고, 성능도 향상됩니다. 또한 쿼리 자체가 비즈니스 로직을 문서화하는 역할을 하여 팀 전체의 생산성이 올라갑니다.

실전 팁

💡 조건이 3개 이상 섞이면 무조건 괄호를 사용하세요. 우선순위를 외우는 것보다 명확한 코드를 작성하는 게 중요합니다.

💡 중첩 괄호가 3단계를 넘어가면 쿼리를 나누는 걸 고려하세요. WITH 절이나 서브쿼리로 단계를 분리하면 가독성이 좋아집니다.

💡 들여쓰기를 활용해 괄호 구조를 시각적으로 표현하세요. 여는 괄호와 닫는 괄호를 같은 들여쓰기 레벨에 두면 실수를 줄일 수 있습니다.

💡 쿼리 테스트 시 괄호 단위로 쪼개서 확인하세요. 각 괄호 안의 조건이 예상대로 동작하는지 먼저 검증하면 디버깅이 쉬워집니다.

💡 팀 코딩 컨벤션을 만드세요. "AND/OR 섞일 때는 항상 괄호 사용"같은 규칙을 정하면 전체 코드 품질이 향상됩니다.


6. 실전 복합 쿼리 작성

시작하며

여러분이 이제까지 배운 AND, OR, NOT, 우선순위, 괄호를 모두 조합하면 실무에서 마주치는 거의 모든 복잡한 조건을 처리할 수 있습니다. 실무 시나리오를 하나 상상해봅시다.

마케팅팀에서 "서울/경기 거주 20-30대 활성 회원 중, VIP이거나 최근 6개월 내 구매 이력이 있지만 이번 달 구매는 없는 고객에게 타겟 프로모션 발송"을 요청합니다. 이런 요구사항을 정확한 SQL로 번역하는 능력이 바로 실전 역량입니다.

바로 이럴 때 필요한 것이 실전 복합 쿼리 작성 능력입니다. 개별 연산자를 이해하는 것을 넘어서, 비즈니스 로직을 정확하고 효율적인 SQL로 변환하는 종합적인 스킬입니다.

개요

간단히 말해서, 실전 복합 쿼리는 여러 논리 연산자와 조건을 체계적으로 조합하여 복잡한 비즈니스 요구사항을 하나의 효율적인 SQL문으로 구현하는 것입니다. 실무에서 이 능력이 중요한 이유는 명확합니다.

실제 프로젝트에서는 단순한 조건으로 해결되는 경우가 거의 없습니다. 고객 세그먼트, 재고 관리, 주문 처리, 권한 체크 등 모든 영역에서 복잡한 조건 로직이 필수입니다.

이를 여러 쿼리나 애플리케이션 코드로 나누면 성능이 저하되고 유지보수가 어려워집니다. 기존에 간단한 쿼리만 작성했다면, 복잡한 요구사항을 만났을 때 당황하거나 비효율적인 방법을 사용했을 겁니다.

하지만 체계적인 접근법을 익히면 어떤 복잡한 조건도 단계적으로 분해하고 조합하여 정확한 쿼리를 작성할 수 있습니다. 실전 복합 쿼리의 핵심 원칙은 네 가지입니다.

첫째, 요구사항을 논리적 단위로 분해합니다. 둘째, 각 단위를 올바른 SQL 조건으로 번역합니다.

셋째, 조건들을 적절한 연산자로 결합하고 괄호로 그룹화합니다. 넷째, 테스트를 통해 검증하고 성능을 확인합니다.

이러한 체계적 접근법을 통해 복잡도에 압도되지 않고 정확한 쿼리를 작성할 수 있습니다.

코드 예제

-- 실전 예제 1: 복잡한 고객 타겟팅
SELECT
    c.customer_id,
    c.customer_name,
    c.city,
    c.membership_type,
    c.last_purchase_date
FROM customers c
WHERE
    -- 조건 그룹 1: 지역과 연령대
    (c.city IN ('서울', '경기') AND c.age BETWEEN 20 AND 39)
    AND
    -- 조건 그룹 2: 회원 상태
    c.status = 'active'
    AND
    -- 조건 그룹 3: VIP이거나 최근 구매 이력
    (c.membership_type = 'VIP'
     OR c.last_purchase_date >= DATE_SUB(CURDATE(), INTERVAL 6 MONTH))
    AND
    -- 조건 그룹 4: 이번 달 구매는 없음
    NOT EXISTS (
        SELECT 1 FROM orders o
        WHERE o.customer_id = c.customer_id
          AND o.order_date >= DATE_FORMAT(CURDATE(), '%Y-%m-01')
    );

-- 실전 예제 2: 재고 관리 쿼리
SELECT
    p.product_id,
    p.product_name,
    p.category,
    p.stock_quantity,
    p.price
FROM products p
WHERE
    -- 조건 그룹 1: 카테고리 필터 (전자기기 또는 가전)
    p.category IN ('전자기기', '가전제품')
    AND
    -- 조건 그룹 2: 재고 부족이거나 과잉 재고
    (p.stock_quantity < 10 OR p.stock_quantity > 1000)
    AND
    -- 조건 그룹 3: 단종 상품은 제외
    p.status != '단종'
    AND
    -- 조건 그룹 4: 가격대 필터
    (p.price BETWEEN 100000 AND 500000 OR p.discount_rate >= 30);

설명

이것이 하는 일: 실전 복합 쿼리는 여러 비즈니스 조건을 논리적으로 분석하고, 각 조건을 SQL 문법으로 정확히 표현한 후, AND/OR/NOT과 괄호를 사용해 하나의 통합된 쿼리로 완성합니다. 첫 번째 예제의 구조를 단계별로 분석해봅시다.

조건 그룹 1에서는 (city IN ('서울', '경기') AND age BETWEEN 20 AND 39)로 지역과 연령대를 필터링합니다. IN 연산자로 여러 도시를 간결하게 표현하고, BETWEEN으로 범위를 명확히 했습니다.

조건 그룹 2는 활성 회원만 선택하는 단순하지만 필수적인 필터입니다. 조건 그룹 3이 핵심입니다.

(membership_type = 'VIP' OR last_purchase_date >= ...)는 VIP 회원이거나 최근 6개월 내 구매자를 선택하는데, 괄호로 묶여 있어서 앞의 AND 조건들과 독립적으로 평가됩니다. 괄호가 없었다면 OR의 낮은 우선순위 때문에 전혀 다른 결과가 나왔을 겁니다.

조건 그룹 4는 서브쿼리와 NOT EXISTS를 활용합니다. 이번 달 주문이 존재하지 않는 고객만 선택하는데, 이는 "재구매 유도" 마케팅 타겟팅에 자주 사용되는 패턴입니다.

서브쿼리에서 현재 월의 시작일(DATE_FORMAT(CURDATE(), '%Y-%m-01'))부터의 주문을 확인합니다. 두 번째 예제는 재고 관리의 실전 시나리오입니다.

조건 그룹 2의 (stock_quantity < 10 OR stock_quantity > 1000)는 재고 부족 또는 과잉 재고 상황을 동시에 찾아내는데, 괄호로 묶여서 하나의 논리 단위로 작동합니다. 조건 그룹 4는 더 흥미롭습니다.

(price BETWEEN 100000 AND 500000 OR discount_rate >= 30)로 "중가 이상 제품이거나 높은 할인률 제품"을 선택합니다. 여러분이 이런 복합 쿼리를 작성할 수 있으면 실무에서 엄청난 가치를 제공합니다.

복잡한 비즈니스 로직을 데이터베이스 레벨에서 처리하면 네트워크 트래픽이 줄고, 애플리케이션 코드가 간결해지며, 전체 시스템 성능이 향상됩니다. 또한 쿼리 자체가 비즈니스 로직의 명확한 문서 역할을 하여 팀 커뮤니케이션도 개선됩니다.

실전 팁

💡 복잡한 쿼리는 주석으로 각 조건 그룹의 의도를 설명하세요. 6개월 후 본인도 쿼리 의도를 까먹을 수 있습니다.

💡 단계적으로 쿼리를 작성하고 테스트하세요. 전체 조건을 한 번에 쓰지 말고, 조건 하나씩 추가하며 결과를 확인하면 디버깅이 쉽습니다.

💡 EXPLAIN 명령으로 쿼리 실행 계획을 확인하세요. 복합 조건이 인덱스를 제대로 활용하는지 검증하는 게 중요합니다.

💡 조건이 5개 이상 넘어가면 WITH 절(CTE)로 단계를 나누는 걸 고려하세요. 가독성과 유지보수성이 크게 향상됩니다.

💡 프로덕션 배포 전 실제 데이터 볼륨으로 성능 테스트를 필수로 하세요. 개발 환경에서는 빠르지만 운영 환경에서 느려지는 경우가 많습니다.


#SQL#논리연산자#WHERE절#복합조건#쿼리최적화#SQL,Database,데이터베이스

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.

함께 보면 좋은 카드 뉴스

SQL 실전 종합 프로젝트 완벽 가이드

전자상거래 시스템을 직접 구축하면서 배우는 SQL 실전 프로젝트입니다. DB 설계부터 성능 최적화까지, 실무에서 필요한 모든 SQL 기술을 단계별로 마스터할 수 있습니다. 초급 개발자도 따라하기 쉬운 친절한 가이드로 구성되어 있습니다.

실무 데이터 분석 SQL 완벽 가이드

실제 업무에서 자주 사용하는 SQL 데이터 분석 기법을 단계별로 학습합니다. 매출 집계부터 고객 세분화까지, 실전 대시보드 쿼리 작성 방법을 배워보세요.

데이터 모델링과 정규화 완벽 가이드

데이터베이스 설계의 핵심인 데이터 모델링과 정규화를 초급 개발자 눈높이에서 쉽게 설명합니다. ERD 작성부터 제1~3정규형, 정규화의 장단점, 비정규화 전략, 실무 설계 패턴까지 실전에서 바로 활용할 수 있는 노하우를 담았습니다.

트랜잭션과 ACID 원칙 완벽 가이드

데이터베이스의 핵심 개념인 트랜잭션과 ACID 원칙을 초급 개발자도 쉽게 이해할 수 있도록 실무 예제와 함께 설명합니다. 안전한 데이터 처리를 위한 필수 지식을 친근하게 배워보세요.

인덱스와 쿼리 성능 최적화 완벽 가이드

데이터베이스 성능의 핵심인 인덱스를 처음부터 끝까지 배워봅니다. B-Tree 구조부터 실행 계획 분석까지, 실무에서 바로 사용할 수 있는 인덱스 최적화 전략을 초급자도 이해할 수 있게 설명합니다.