VMware ESXi and vSphere Cluster Management
SQL IN Operator: Filter Rows by Multiple Values
Learn how to use SQL IN and NOT IN in WHERE clauses, compare IN with OR, handle NULL values, and filter with subqueries.
The SQL IN operator tests whether an expression matches any value in a supplied set. It is commonly used in a WHERE clause, the part of a query that filters rows according to a condition.
For example, instead of writing several equality comparisons joined with OR, you can write one concise IN condition:
WHERE lastName IN ('Patterson', 'Bow')
A condition such as this is called a predicate. For each row, the predicate evaluates to true, false, or unknown.
Basic IN syntax
SELECT column_list
FROM table_name
WHERE column_name IN (value1, value2, ...);
SELECT column_listspecifies the columns to return. UseSELECT *to return every column, or name only the columns needed.FROM table_nameidentifies the table being queried.WHEREbegins the row-filtering condition.column_nameis the expression being tested.- The parentheses contain the value list: comma-separated values that are acceptable matches.
- Each listed value must be compatible with the tested column's data type.
The predicate is true when the tested value equals at least one item in the list.
Matching text values
Suppose an employees table contains these rows:
lastName firstName extension
Murphy Diane x5800
Patterson Mary x4611
Patterson William x4871
Bow Anthony x5428
Patterson Steve x4334
To retrieve every employee whose last name is Patterson or Bow, use:
SELECT *
FROM employees
WHERE lastName IN ('Patterson', 'Bow');
Text values are string literals. In standard SQL, string literals are written with single quotes.
The query returns these matching rows:
lastName firstName extension
Patterson Mary x4611
Patterson William x4871
Bow Anthony x5428
Patterson Steve x4334
Each returned row matches one of the values in the list: the Patterson rows match 'Patterson', and Anthony Bow matches 'Bow'. Murphy is excluded because 'Murphy' is not in the list.
Select only the columns you need
SELECT lastName, firstName, extension
FROM employees
WHERE lastName IN ('Patterson', 'Bow');
This applies the same filter but returns a narrower result set. Selecting specific columns is often clearer and avoids transferring unnecessary data.
IN compared with OR
The equivalent condition using repeated equality comparisons is:
SELECT lastName, firstName, extension
FROM employees
WHERE lastName = 'Patterson'
OR lastName = 'Bow';
For ordinary non-NULL values, this produces the same matching rows as the IN query. IN is usually easier to read when the same column is compared with several possible values.
-- Concise form
WHERE lastName IN ('Patterson', 'Bow')
-- Equivalent OR form
WHERE lastName = 'Patterson'
OR lastName = 'Bow'
OR remains useful when the conditions are different, such as comparisons involving different columns or operators.
WHERE lastName = 'Patterson'
OR employeeNumber > 1100
Here, the conditions do not form a simple list of values for one column, so IN is not a direct replacement.
Using IN with other data types
IN can test numbers as well as text:
SELECT employeeNumber, lastName, firstName
FROM employees
WHERE employeeNumber IN (1002, 1056, 1088);
Numeric literals are written without quotes. Avoid quoting numbers unless the column is actually character-based. Quoted values can cause implicit type conversion, errors, or inefficient comparisons depending on the database system.
Date and text literal syntax can vary between database systems. Follow the rules for your database, and make sure the values are compatible with the type of the column being tested.
- Text example:
lastName IN ('Patterson', 'Bow') - Numeric example:
employeeNumber IN (1002, 1056, 1088) - Date example: use the date-literal format supported by your database.
NOT IN
NOT IN is the negated form of IN. It selects rows whose value is not equal to any value in the list.
SELECT lastName, firstName
FROM employees
WHERE lastName NOT IN ('Patterson', 'Bow');
This excludes employees with either of those last names. However, a row whose lastName is NULL is not automatically included, because the comparison result is unknown.
IN with a subquery
Instead of a literal value list, the parenthesized source can be a subquery, which is a query nested inside another SQL statement.
SELECT employeeNumber, lastName, firstName, officeCode
FROM employees
WHERE officeCode IN (
SELECT officeCode
FROM offices
WHERE country = 'USA'
);
The inner query returns a single column containing office codes for offices in the USA. The outer query returns employees whose officeCode appears among those results.
An IN subquery must return exactly one column, and that column must have a compatible data type with the outer expression. The subquery may return multiple rows.
- Use a literal list when the accepted values are a small, known set:
status IN ('new', 'open'). - Use a subquery when the accepted values come from current database data:
officeCode IN (SELECT officeCode ...).
NULL and SQL three-valued logic
NULL represents an unknown or missing value. It is not the same as zero, an empty string, or a normal text value.
SQL uses three-valued logic: a predicate can be true, false, or unknown. A WHERE clause returns only rows for which its predicate is true.
Do not use IN (NULL) to find missing values
-- Incorrect for finding NULL values
WHERE extension IN (NULL)
IN (NULL) does not match rows where extension is NULL. Equality-style comparisons with an unknown value produce unknown rather than true.
Use IS NULL instead:
SELECT lastName, firstName, extension
FROM employees
WHERE extension IS NULL;
Similarly, use IS NOT NULL when you need values that are present. Do not write extension = NULL to find missing values.
Why NULL affects NOT IN
Consider a subquery used with NOT IN. If the subquery returns values such as 10, 20, and NULL, SQL cannot establish that an outer value is different from every returned value. The predicate can therefore evaluate to unknown for every outer row, causing the query to return no rows.
-- Potentially unsafe when officeCode can be NULL
WHERE officeCode NOT IN (
SELECT officeCode
FROM offices_to_skip
);
When appropriate, exclude nulls from the subquery:
WHERE officeCode NOT IN (
SELECT officeCode
FROM offices_to_skip
WHERE officeCode IS NOT NULL
);
Another common solution is NOT EXISTS, which can express the exclusion without the same NULL trap:
WHERE NOT EXISTS (
SELECT 1
FROM offices_to_skip AS skipped
WHERE skipped.officeCode = employees.officeCode
);
Practical query-writing guidance
Format longer lists clearly
Put one value per line when a list is long enough to be difficult to scan:
SELECT employeeNumber, lastName
FROM employees
WHERE employeeNumber IN (
1002,
1056,
1088,
1102
);
Handle empty lists
An empty list such as IN () is invalid in many SQL dialects. Application code should handle an empty collection before constructing the query. Decide explicitly whether an empty collection should mean no matching rows or no filtering, then generate a safe query for that behavior.
Use parameters for application input
When values come from an application, use a parameterized query rather than concatenating user-provided text into SQL. A parameterized query supplies runtime values separately from the SQL text, reducing syntax problems and helping prevent SQL injection.
-- Conceptual form; parameter syntax varies by driver
SELECT employeeNumber, lastName
FROM employees
WHERE employeeNumber IN (?, ?, ?);
Your database driver may use named parameters or a different placeholder style. Bind the values through the driver instead of inserting them into the SQL string.
Consider another design for very large lists
A very large hard-coded list can be difficult to maintain and may be inefficient. Depending on the database and application, store the values in a temporary or staging table, join to that table, or use a subquery. These approaches make the values data rather than a large SQL expression.
Common problems and fixes
- Text does not match: use single-quoted values such as
IN ('Patterson', 'Bow'), then check spelling, case behavior, and extra whitespace in the stored data. IN (NULL)returns no missing rows: useIS NULL.NOT INwith a subquery returns no rows: check whether the subquery returnsNULL; filter it out or rewrite the condition withNOT EXISTS.- The subquery raises an error: select exactly one compatible column inside the
INsubquery. - A large list is slow or hard to maintain: move the values into a table and use a join or subquery.
- Generated SQL contains
IN (): handle the empty input case before executing the statement.
Quick reference
-- Literal list
SELECT column_list
FROM table_name
WHERE column_name IN (value1, value2, ...);
-- Exclusion list
SELECT column_list
FROM table_name
WHERE column_name NOT IN (value1, value2, ...);
-- One-column subquery
SELECT column_list
FROM table_name
WHERE column_name IN (
SELECT related_column
FROM related_table
WHERE condition
);
-- Find missing values
SELECT column_list
FROM table_name
WHERE column_name IS NULL;
For a concise rule to remember: use IN for a known set of acceptable values, use a subquery when that set comes from table data, and check NULL behavior whenever you use NOT IN.