Glossary/SQL Filtering — WHERE, Operators, LIKE, IN, BETWEEN, NULL
SQL & Databases

SQL Filtering — WHERE, Operators, LIKE, IN, BETWEEN, NULL

Extracting exactly the rows you need using conditions, patterns, and ranges.


Definition

The WHERE clause filters rows based on conditions. SQL provides a rich set of operators: comparison operators (=, >, <, >=, <=, !=), logical operators (AND, OR, NOT), range operators (BETWEEN), membership operators (IN), pattern matching (LIKE with wildcards), and null checks (IS NULL, IS NOT NULL). EXISTS checks whether a subquery returns any rows. Mastering filtering is the most used SQL skill in day-to-day database work.

Real-life analogy: The search filter

An e-commerce search with filters is WHERE in action: price BETWEEN 500 AND 2000, brand IN ('Nike','Adidas'), name LIKE '%running%', discount IS NOT NULL. Every filter panel on every website is powered by SQL WHERE clauses behind the scenes.

Comparison and logical operators

All filtering operators with examples

-- COMPARISON OPERATORS
SELECT * FROM Employee WHERE Salary > 50000;
SELECT * FROM Employee WHERE Salary >= 50000;
SELECT * FROM Employee WHERE Salary < 30000;
SELECT * FROM Employee WHERE Status = 'Active';
SELECT * FROM Employee WHERE Status != 'Terminated';  -- Or: <> 'Terminated'

-- LOGICAL OPERATORS (AND, OR, NOT)
SELECT * FROM Employee
WHERE DeptID = 1 AND Salary > 50000;         -- Both conditions must be true

SELECT * FROM Employee
WHERE DeptID = 1 OR DeptID = 2;              -- Either condition true

SELECT * FROM Employee
WHERE NOT Status = 'Terminated';             -- Negation

-- Operator precedence: NOT > AND > OR
-- Use parentheses to be explicit:
SELECT * FROM Employee
WHERE (DeptID = 1 OR DeptID = 2)             -- Group OR first
  AND Salary > 50000                         -- Then AND
  AND NOT Status = 'Inactive';

-- BETWEEN (inclusive on both ends)
SELECT * FROM Employee WHERE Salary BETWEEN 40000 AND 80000;
-- Equivalent to: WHERE Salary >= 40000 AND Salary <= 80000
SELECT * FROM Orders WHERE OrderDate BETWEEN '2024-01-01' AND '2024-12-31';

-- IN (membership check — cleaner than multiple ORs)
SELECT * FROM Employee WHERE DeptID IN (1, 2, 5, 8);
-- Equivalent to: WHERE DeptID=1 OR DeptID=2 OR DeptID=5 OR DeptID=8

SELECT * FROM Employee WHERE DeptID NOT IN (3, 4);

-- IN with subquery
SELECT * FROM Employee
WHERE DeptID IN (SELECT DeptID FROM Department WHERE Budget > 500000);

-- IS NULL / IS NOT NULL
SELECT * FROM Employee WHERE ManagerID IS NULL;      -- Top-level managers
SELECT * FROM Employee WHERE ManagerID IS NOT NULL;  -- Employees with manager

-- Combine all
SELECT Name, Salary, DeptID FROM Employee
WHERE DeptID IN (1, 2, 3)
  AND Salary BETWEEN 30000 AND 100000
  AND Status IS NOT NULL
  AND Name != 'Admin'
ORDER BY Salary DESC;

LIKE — pattern matching with wildcards

LIKE patterns with % and _ wildcards

-- % wildcard: matches ANY number of characters (including zero)
SELECT * FROM Employee WHERE Name LIKE 'R%';         -- Starts with R
SELECT * FROM Employee WHERE Name LIKE '%kumar';     -- Ends with kumar
SELECT * FROM Employee WHERE Email LIKE '%@gmail%';  -- Contains @gmail
SELECT * FROM Employee WHERE Name LIKE '%ra%';       -- Contains 'ra' anywhere

-- _ wildcard: matches EXACTLY ONE character
SELECT * FROM Employee WHERE Code LIKE 'EMP___';     -- EMP + exactly 3 chars
SELECT * FROM Employee WHERE Phone LIKE '98_______'; -- Starts 98 + 7 any chars

-- ILIKE (case-insensitive LIKE — PostgreSQL)
SELECT * FROM Employee WHERE Name ILIKE 'ravi%';     -- Matches Ravi, RAVI, ravi

-- LIKE with special characters (escape the % itself)
SELECT * FROM Product WHERE Description LIKE '100% discount' ESCAPE '';

-- NOT LIKE
SELECT * FROM Employee WHERE Email NOT LIKE '%@yahoo%';

-- Performance tip: Leading % disables index use
-- LIKE 'Ravi%'  → Can use index (prefix match)
-- LIKE '%Ravi%' → Full table scan (no index benefit)
-- Use full-text search for contains queries on large tables

-- SIMILAR TO (PostgreSQL: regex-like pattern)
SELECT * FROM Employee WHERE Phone SIMILAR TO '(98|99)[0-9]{8}';

-- REGEXP (MySQL)
SELECT * FROM Employee WHERE Name REGEXP '^[AEIOUaeiou]';  -- Starts with vowel

EXISTS and NOT EXISTS

EXISTS vs IN — when to use each

-- EXISTS: returns TRUE if subquery returns at least one row
-- Short-circuits as soon as first match found — efficient for large tables

-- Find employees who manage at least one other employee
SELECT e.Name FROM Employee e
WHERE EXISTS (
    SELECT 1 FROM Employee mgr WHERE mgr.ManagerID = e.EmpID
);

-- NOT EXISTS: find employees with NO subordinates
SELECT e.Name FROM Employee e
WHERE NOT EXISTS (
    SELECT 1 FROM Employee mgr WHERE mgr.ManagerID = e.EmpID
);

-- EXISTS vs IN comparison:
-- IN: executes subquery fully, stores result, then checks membership
SELECT Name FROM Employee WHERE DeptID IN (SELECT DeptID FROM Department WHERE Budget > 500000);

-- EXISTS: correlated — executes once per outer row, stops at first match
SELECT e.Name FROM Employee e
WHERE EXISTS (SELECT 1 FROM Department d WHERE d.DeptID = e.DeptID AND d.Budget > 500000);

-- EXISTS is generally faster when:
-- 1. Subquery returns many rows (IN stores all of them)
-- 2. You only need to know IF a match exists (EXISTS short-circuits)
-- IN is fine for small, static lists
OperatorReturns rows whenNULL handlingPerformance
= valueColumn equals exact valueNULL = anything → FALSEUses index if available
IN (list)Column matches any value in listNULL in list causes no matchUses index; large IN lists may be slow
BETWEEN a AND bColumn in range [a, b] inclusiveNULLs excludedUses range index scan
LIKE patternColumn matches wildcard patternNULLs excludedIndex only for prefix patterns
IS NULLColumn has no valueCorrectly identifies NULLsUsually full scan
EXISTS (sub)Subquery returns >= 1 rowNULLs in subquery handled correctlyShort-circuits — often fastest

Practice questions

  1. BETWEEN 10 AND 20 — is 20 included? (Answer: Yes — BETWEEN is inclusive on both ends. Equivalent to >= 10 AND <= 20.)
  2. Find all employees whose name contains exactly 4 characters. (Answer: WHERE Name LIKE '____' — four underscore wildcards, each matching exactly one character.)
  3. Why does WHERE column IN (1, 2, NULL) not return rows where column IS NULL? (Answer: NULL compared with = (or IN which uses =) always yields UNKNOWN, not TRUE. Use OR column IS NULL explicitly.)
  4. NOT IN vs NOT EXISTS — when does NOT IN fail silently? (Answer: NOT IN fails if the subquery returns any NULL — NOT IN (1, 2, NULL) is equivalent to != 1 AND != 2 AND != NULL, and != NULL is always UNKNOWN, so no rows are returned. NOT EXISTS handles NULLs correctly.)
  5. LIKE '%word%' cannot use an index. What is the alternative for fast full-text contains search? (Answer: Full-text search indexes (PostgreSQL: GIN index with tsvector/tsquery, MySQL: FULLTEXT index). These tokenise text and support fast contains/relevance queries.)

On LumiChats

LumiChats can build any SQL WHERE clause from a plain English description: 'Find all customers from Mumbai who placed orders above 5000 in the last 6 months' — generates the correct WHERE with LIKE, BETWEEN, and date comparison.

Try it free

Try LumiChats for ₹69

39+ AI models. Study Mode with page-locked answers. Agent Mode with code execution. Pay only on days you use it.

Get Started — ₹69/day

Related Terms

3 terms