πŸŽ‰ 75% of content is free forever β€” Unlock Premium from $10/mo β†’
CW
Search courses…
πŸ’Ό Servicesℹ️ Aboutβœ‰οΈ ContactView Pricing Plansfrom $10

IN and BETWEEN Operators

SQL FundamentalsDML🟒 Free Lesson

Advertisement

SQL Fundamentals

IN and BETWEEN Operators

Check if a value matches any value in a list with IN, or falls within a range with BETWEEN.

  • IN Operator β€” Match against a list of values
  • BETWEEN Operator β€” Match within an inclusive range
  • NOT IN / NOT BETWEEN β€” Negate both operators Simplify complex OR conditions and range checks.

What Are IN and BETWEEN?

DfSet and Range Operators

IN checks whether a value matches any value in a specified list. BETWEEN checks whether a value falls within an inclusive range (both endpoints included). Both simplify WHERE clause conditions and improve readability.

IN β€” Set Membership1020304050WHERE val IN (10,20,30,50)40 is NOT in the setBETWEEN β€” Range60k80kWHERE val BETWEEN 60000 AND 80000Inclusive on both ends
-- IN: match against a list
SELECT * FROM employees WHERE department IN ('Engineering', 'Sales');

-- BETWEEN: match within a range
SELECT * FROM employees WHERE salary BETWEEN 60000 AND 80000;
BETWEEN is inclusive on both ends. BETWEEN 60000 AND 80000 includes salaries of exactly 60000 and exactly 80000.

IN Operator

IN replaces multiple OR conditions on the same column with a cleaner syntax.

DfIN Operator

column IN (value1, value2, ...) Returns TRUE if the column value matches any value in the list. Works with numbers, strings, and dates.

-- IN with numeric values
SELECT * FROM products
WHERE category_id IN (1, 2, 3, 4, 5);
-- IN with string values
SELECT * FROM customers
WHERE country IN ('USA', 'Canada', 'Mexico');
-- IN with date values
SELECT * FROM orders
WHERE order_date IN ('2024-01-01', '2024-06-15', '2024-12-31');
-- IN is equivalent to multiple OR conditions
-- These two queries return the same result:
SELECT * FROM employees WHERE department IN ('Engineering', 'Sales', 'Marketing');
SELECT * FROM employees
WHERE department = 'Engineering'
OR department = 'Sales'
OR department = 'Marketing';
OperatorSyntaxExample
INcolumn IN (list)WHERE id IN (1, 2, 3)
Multiple ORcol = v1 OR col = v2WHERE id = 1 OR id = 2 OR id = 3

IN with Subqueries

IN becomes powerful when the list is generated dynamically from another table.

DfIN with Subquery

column IN (SELECT expression FROM table WHERE condition) The subquery returns a list of values. The outer query includes rows where the column matches any value in that list.

-- Find customers who have placed orders
SELECT first_name, last_name
FROM customers
WHERE id IN (SELECT DISTINCT customer_id FROM orders);
-- Find products in active categories
SELECT * FROM products
WHERE category_id IN (
    SELECT category_id
    FROM categories
    WHERE status = 'Active'
);
-- Find employees in high-budget departments
SELECT * FROM employees
WHERE department_id IN (
    SELECT department_id
    FROM departments
    WHERE budget > 1000000
);
IN with a subquery that returns NULLs can cause unexpected behavior. A NULL in the list makes comparisons involving IN evaluate to UNKNOWN for non-matching rows.

NOT IN

NOT IN returns rows where the column value does not match any value in the list.

-- Find employees NOT in specific departments
SELECT * FROM employees
WHERE department NOT IN ('Engineering', 'Sales');
-- Find customers who have never placed orders
SELECT * FROM customers
WHERE id NOT IN (SELECT DISTINCT customer_id FROM orders);
NOT IN with a subquery containing NULLs returns NO rows at all. If any value in the subquery is NULL, the entire NOT IN condition becomes UNKNOWN. Use NOT EXISTS or LEFT JOIN instead for reliable behavior.
-- Safer alternative: NOT EXISTS
SELECT * FROM customers c
WHERE NOT EXISTS (
    SELECT 1 FROM orders o
    WHERE o.customer_id = c.id
);

-- Also safe: LEFT JOIN
SELECT c.* FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
WHERE o.customer_id IS NULL;

BETWEEN Operator

BETWEEN checks whether a value falls within an inclusive range. It works with numbers, strings, and dates.

DfBETWEEN Operator

column BETWEEN start AND end Equivalent to column >= start AND column <= end. Both endpoints are included.

-- Numeric range
SELECT * FROM products
WHERE price BETWEEN 50 AND 100;
-- String range (alphabetical ordering)
SELECT * FROM customers
WHERE last_name BETWEEN 'A' AND 'M';
-- Date range
SELECT * FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-03-31';
-- NOT BETWEEN
SELECT * FROM employees
WHERE salary NOT BETWEEN 50000 AND 80000;
ExpressionEquivalent To
x BETWEEN a AND bx >= a AND x <= b
x NOT BETWEEN a AND bx < a OR x > b

BETWEEN with DateTime

DateTime ranges require careful handling because BETWEEN is inclusive on both ends.

DfDateTime BETWEEN

When using BETWEEN with datetime columns, the end value must include the time component to capture all rows on the end date. Otherwise, rows with times after midnight are excluded.

-- Incorrect: misses orders on Jan 31 after midnight
SELECT * FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-01-31';

-- Correct: includes all of Jan 31
SELECT * FROM orders
WHERE order_date BETWEEN '2024-01-01 00:00:00' AND '2024-01-31 23:59:59';
-- Current year orders using functions
SELECT * FROM orders
WHERE order_date BETWEEN
    DATE_FORMAT(CURRENT_DATE, '%Y-01-01')
    AND DATE_FORMAT(CURRENT_DATE, '%Y-12-31');
For datetime columns, consider using column >= start AND column < end_plus_one to avoid time component issues entirely.

Performance Considerations

DfIN and BETWEEN Performance

Both operators can use indexes effectively. IN with a short list is optimized to range scans. BETWEEN always uses range scans. For very large IN lists, consider temporary tables or JOINs.

-- IN can use indexes
SELECT * FROM employees
WHERE department IN ('Engineering', 'Sales', 'Marketing');

-- BETWEEN uses range scan
SELECT * FROM orders
WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31';
-- For very large IN lists, consider a JOIN
SELECT e.* FROM employees e
INNER JOIN (
    SELECT 'Engineering' AS dept
    UNION ALL SELECT 'Sales'
    UNION ALL SELECT 'Marketing'
) d ON e.department = d.dept;
OperatorIndex UsageBest For
IN (small list)Range scanFew discrete values
IN (large list)May degradeConsider JOIN
BETWEENRange scanContinuous ranges
NOT INSometimesPrefer NOT EXISTS
NOT BETWEENRange scanExclusion ranges

Practice Exercises

Exercise 1: Find all Electronics or Clothing products priced between 20and20 and100.

-- Solution
SELECT * FROM products
WHERE category IN ('Electronics', 'Clothing')
AND price BETWEEN 20 AND 100;

Exercise 2: Find customers from major cities who registered in 2024.

-- Solution
SELECT * FROM customers
WHERE city IN ('New York', 'Los Angeles', 'Chicago')
AND registration_date BETWEEN '2024-01-01' AND '2024-12-31';

Exercise 3: Find orders that are NOT in pending or cancelled status.

-- Solution
SELECT * FROM orders
WHERE status NOT IN ('Pending', 'Cancelled');

Summary

Key Takeaways

  1. IN checks if a value matches any value in a list
  2. BETWEEN checks if a value falls within an inclusive range
  3. Both work with numbers, strings, and dates
  4. NOT IN and NOT BETWEEN negate the conditions
  5. NOT IN with NULLs returns no rows β€” use NOT EXISTS instead
  6. BETWEEN is inclusive on both endpoints
  7. DateTime BETWEEN requires careful handling of the time component
  8. Both operators can leverage indexes for good performance
OperatorUse CaseNegation
INMatch a list of valuesNOT IN
BETWEENMatch an inclusive rangeNOT BETWEEN
EXISTSMatch subquery resultsNOT EXISTS
LIKEPattern matchingNOT LIKE
⭐

Premium Content

IN and BETWEEN Operators

Unlock this lesson and 900+ advanced tutorials with a Premium plan.

🎯End-to-end Projects
πŸ’ΌInterview Prep
πŸ“œCertificates
🀝Community Access

Already a member? Log in

Need Expert SQL Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement