- 1 1. What Is the MySQL NOT IN Clause? — Making Data Exclusion More Efficient
- 2 2. Basic Syntax and Usage Examples of NOT IN
- 3 3. Important Notes When NULL Values Are Present
- 4 4. NOT IN vs NOT EXISTS — Comparing Alternatives
- 5 5. Performance Considerations
- 6 6. Common Use Cases and Advanced Techniques
- 7 7. FAQ (Frequently Asked Questions)
- 8 8. Conclusion
1. What Is the MySQL NOT IN Clause? — Making Data Exclusion More Efficient
When working with databases in MySQL, there are surprisingly many situations where you need to retrieve data while “excluding” specific values or conditions. For example, you may want to display a list of users except those who have unsubscribed, or aggregate data excluding IDs that appear in a blacklist. These scenarios frequently occur in business and development environments. This is where the NOT IN clause becomes extremely useful.
The NOT IN clause is a powerful SQL condition that allows you to easily extract only the data that does not match specified values or the results of a subquery. In addition to simple exclusion using a list, combining it with dynamic subqueries enables various exclusion patterns.
However, depending on how it is used, NOT IN has certain caveats and potential pitfalls. In particular, its behavior when NULL values are involved, performance issues in large databases, and differences compared to NOT EXISTS are all important points to understand at a practical level.
In this article, we thoroughly explain the MySQL NOT IN clause—from the basics to advanced usage—along with precautions and comparisons with alternative exclusion methods, using concrete examples. Whether you are new to SQL or already work with it regularly, this guide provides valuable insights. Be sure to read through to the end and use this knowledge to improve your SQL skills and optimize your workflow.
2. Basic Syntax and Usage Examples of NOT IN
The NOT IN clause in MySQL is used when you want to retrieve records that do not match any of several specified values. The syntax itself is simple, but in real-world scenarios, it proves useful in many situations. Here, we introduce the basic syntax and practical examples.
[Basic Syntax]
SELECT column_name FROM table_name WHERE column_name NOT IN (value1, value2, ...);Exclusion Using a Simple List
For example, if you want to retrieve users whose names are not “Yamada” or “Sato,” you would write the following SQL statement:
SELECT * FROM users WHERE name NOT IN ('Yamada', 'Sato');Executing this query retrieves all user records except those named “Yamada” and “Sato.” Since the exclusion list only requires comma-separated values, it is easy to write and understand.
Dynamic Exclusion Using a Subquery
The NOT IN clause can also use a subquery inside the parentheses, not just a fixed list. This is particularly useful when you want to exclude user IDs that meet specific conditions.
SELECT * FROM users
WHERE id NOT IN (SELECT user_id FROM blacklist WHERE is_active = 1);In this example, user IDs that are marked as active in the blacklist table (is_active = 1) are excluded, and the remaining users are retrieved from the users table. By combining NOT IN with subqueries, you can flexibly adapt to various business logic requirements.
Applying Multiple Conditions
If you need to specify exclusion conditions across multiple columns simultaneously, NOT IN is primarily designed for single-column use. However, by combining it with subqueries or joins (JOIN), you can handle more complex conditions. We will explain this in detail in the advanced techniques section later.
As you can see, the NOT IN clause is extremely useful when you want to retrieve all records except those included in a specified list or subquery result. Start by visualizing the data you want to extract, and practice using both simple exclusion lists and subqueries effectively.
3. Important Notes When NULL Values Are Present
When using the NOT IN clause, one commonly overlooked issue is its behavior when NULL values are involved. This is a classic “pitfall” that can cause mistakes not only for beginners but even for experienced SQL users.
The reason is that the evaluation logic of NOT IN differs from normal comparisons—it behaves differently when NULL values are included.
Behavior When NULL Is Included
Suppose we have the following tables:
-- users table
id | name
---+------
1 | Sato
2 | Yamada
3 | Suzuki
4 | Tanaka
-- blacklist table
user_id
--------
1
NULLNow consider executing the following SQL statement:
SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM blacklist);At first glance, it may seem that all users except user_id = 1 (that is, id = 2, 3, 4) would be returned. However, in reality, no rows are returned.
Why Are No Rows Returned?
The reason lies in SQL’s three-valued logic (TRUE / FALSE / UNKNOWN).
When NULL is included in the NOT IN list, the comparison result becomes UNKNOWN, and MySQL does not include those rows in the result set.
In other words, since it cannot definitively determine that a value does not match any item in the list, the overall condition evaluates to false.
Common Trouble Scenarios
This issue frequently occurs when using subqueries. If NULL values exist in a blacklist or unsubscribe list, data may not be retrieved as expected.
Problems such as “no data is returned” or “records are not properly excluded” often trace back to hidden NULL values.
Countermeasures and Workarounds
To prevent issues caused by NULL values, you must exclude NULL from the NOT IN list. Specifically, add an IS NOT NULL condition inside the subquery.
SELECT * FROM users
WHERE id NOT IN (
SELECT user_id FROM blacklist WHERE user_id IS NOT NULL
);With this adjustment, even if the blacklist table contains NULL values, the query will correctly retrieve users who are not on the blacklist.
Key Points
- If NULL exists in a
NOT INlist, the query may return zero rows - Always combine subqueries with
IS NOT NULLwhen usingNOT IN - If data is unexpectedly missing, check for hidden NULL values first
4. NOT IN vs NOT EXISTS — Comparing Alternatives
When specifying exclusion conditions in MySQL, NOT EXISTS is another common alternative to NOT IN. While both can achieve similar results, they differ in behavior, NULL handling, and performance characteristics. In this section, we compare NOT IN and NOT EXISTS, and explain their respective advantages and disadvantages.
Basic Syntax Comparison
[Exclusion Using NOT IN]
SELECT * FROM users
WHERE id NOT IN (SELECT user_id FROM blacklist WHERE user_id IS NOT NULL);[Exclusion Using NOT EXISTS]
SELECT * FROM users u
WHERE NOT EXISTS (
SELECT 1 FROM blacklist b WHERE b.user_id = u.id
);Both queries retrieve users who are not registered in the blacklist.
Handling NULL Values
NOT IN
- If
NULLis included in the list or subquery result, the query may not behave as expected (it may return zero rows) - Requires an explicit
IS NOT NULLcondition as a safeguard
NOT EXISTS
- Works correctly even if the subquery result contains
NULL - Generally safer because it is not affected by NULL values
Performance Differences
The optimal approach depends on data volume and table structure, but generally:
- For small datasets or fixed lists,
NOT INperforms adequately - For large subqueries or complex conditions,
NOT EXISTSorLEFT JOINoften provides better performance
As the number of blacklist records increases, NOT EXISTS frequently becomes more efficient. Depending on the MySQL version and indexing, NOT EXISTS can be very fast when proper indexes are available, since it performs an existence check for each row.
Guidelines for Choosing
- If NULL values may be present
→ UseNOT EXISTS - If excluding a fixed list or simple values
→NOT INis sufficient - If performance is critical
→ Check the execution plan with EXPLAIN and choose accordingly (consider JOIN orNOT EXISTS)
Sample Cases
Problematic Example Using NOT IN
-- If blacklist.user_id contains NULL
SELECT * FROM users
WHERE id NOT IN (SELECT user_id FROM blacklist);
-- → May return zero rowsSafe Exclusion Example Using NOT EXISTS
SELECT * FROM users u
WHERE NOT EXISTS (
SELECT 1 FROM blacklist b WHERE b.user_id = u.id
);
-- → Correct results regardless of NULL valuesSummary
NOT INis simple but vulnerable to NULL valuesNOT EXISTSis robust against NULL and widely used in production environments- Choose based on data characteristics and required performance
5. Performance Considerations
When working with large datasets in SQL, query performance is extremely important. Depending on conditions and data volume, using NOT IN or NOT EXISTS can result in significant differences in execution speed. In this section, we focus on the performance impact of the NOT IN clause, along with optimization tips and important considerations.
Performance Characteristics of NOT IN
The NOT IN clause retrieves records that do not match any values in a specified list or subquery result. It performs efficiently with small lists or tables, but may slow down in the following situations:
- When the subquery returns a large number of rows
- When the excluded column is not indexed
- When NULL values are present in the subquery result
In particular, if the subquery contains tens of thousands or hundreds of thousands of rows and no index is defined, MySQL may perform full comparisons, leading to significant slowdowns.
The Importance of Indexing
Adding an index to the column used for exclusion (for example, user_id) allows MySQL to perform comparisons and filtering more efficiently. Columns used in subqueries or joins should be indexed whenever appropriate.
CREATE INDEX idx_blacklist_user_id ON blacklist(user_id);By adding an index like this, the performance of NOT IN and NOT EXISTS queries can improve dramatically.

Performance Comparison: NOT IN vs NOT EXISTS
- Small, fixed lists:
NOT INis typically fast - Large subqueries:
NOT EXISTSorLEFT JOINis often more efficient
Because MySQL’s execution plan (EXPLAIN result) varies depending on version and table design, performance optimization should always involve actual testing.
Checking the Execution Plan with EXPLAIN
To determine which query performs better, use MySQL’s EXPLAIN command:
EXPLAIN SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM blacklist WHERE user_id IS NOT NULL);This allows you to see which indexes are used and whether any tables are being fully scanned—information that directly impacts performance.
Optimization Strategies for Large Datasets
- Store intermediate results in a temporary table to reduce subquery load
- Use batch processing or caching if performance is still insufficient
- Rewrite using
LEFT JOIN ... IS NULL(in some cases this improves speed)
Key Points
NOT INcan become slow when subqueries are large or indexes are missing- Proper index design and query review can significantly improve performance
- Consider
NOT EXISTSorLEFT JOIN, and always verify results using EXPLAIN
In production environments, always choose the most appropriate query based on data scale and usage frequency.
6. Common Use Cases and Advanced Techniques
The NOT IN clause is not limited to simple exclusions. With advanced techniques, you can perform more flexible data extraction. Here we introduce commonly used patterns and practical techniques.
Excluding Multiple Columns (Composite Key Exclusion)
While NOT IN is typically used for a single column, there are cases where you need to exclude combinations of multiple columns. In such situations, NOT EXISTS or LEFT JOIN is more suitable.
[Example: Excluding specific combinations of customer_id and product_id from the orders table]
SELECT * FROM orders o
WHERE NOT EXISTS (
SELECT 1 FROM blacklist b
WHERE b.customer_id = o.customer_id
AND b.product_id = o.product_id
);This excludes all “customer_id × product_id” combinations registered in the blacklist.
Partial Match Exclusion (Using NOT LIKE)
Since NOT IN only works with exact matches, use NOT LIKE when excluding specific string patterns. For example, to exclude users whose email addresses start with “test@”:
SELECT * FROM users WHERE email NOT LIKE 'test@%';To exclude multiple patterns at once, combine conditions with AND:
SELECT * FROM users
WHERE email NOT LIKE 'test@%'
AND email NOT LIKE 'sample@%';Handling Large Exclusion Lists
Listing hundreds or thousands of values directly inside NOT IN reduces readability and may hurt performance.
In such cases, use a dedicated table or subquery to manage the exclusion list more cleanly:
-- Example: Store exclusion list in blacklist table
SELECT * FROM users
WHERE id NOT IN (SELECT user_id FROM blacklist WHERE user_id IS NOT NULL);Combining with Aggregate Functions
You can also use NOT IN with subqueries that contain aggregate conditions.
[Example: Retrieve customers who did not place orders this month]
SELECT * FROM customers
WHERE id NOT IN (
SELECT customer_id FROM orders
WHERE order_date >= '2025-06-01'
AND order_date < '2025-07-01'
);Using JOIN Instead of a Subquery
In some cases, you can achieve the same result using LEFT JOIN combined with IS NULL.
Choose the most appropriate method based on performance and readability.
SELECT u.*
FROM users u
LEFT JOIN blacklist b ON u.id = b.user_id
WHERE b.user_id IS NULL;This approach is especially useful when subquery performance is uncertain or when indexes are effective.
Key Points
- Use
NOT EXISTSor JOIN for multi-column exclusion - Combine with
NOT LIKEfor partial string exclusions - Manage large exclusion lists using tables or subqueries
JOIN + IS NULLmay also improve performance
7. FAQ (Frequently Asked Questions)
Here are some frequently asked questions and common stumbling points regarding the MySQL NOT IN clause. The answers focus on practical issues that are often searched for in real-world scenarios.
Q1. What is the difference between NOT IN and IN?
A.IN retrieves data that matches any value in a specified list, whereas NOT IN retrieves only data that does not match any value in the list. Their syntax is nearly identical, but if you want to exclude certain values, you should use NOT IN.
Q2. What happens if NULL values exist when using NOT IN?
A.
If NULL values are included in the list or subquery, NOT IN may return zero rows or produce unexpected results. It is safest to exclude NULL explicitly using IS NOT NULL.
Q3. How should I choose between NOT IN and NOT EXISTS?
A.
- If NULL values are possible or a subquery is involved,
NOT EXISTSis more reliable. - For fixed lists or simple exclusions,
NOT INworks fine. - Since performance may vary depending on execution plans and data volume, choose based on your specific scenario.
Q4. Sometimes queries using NOT IN are slow. What can I do?
A.
- Add an index to the column used in the exclusion condition
- Reduce the size of the subquery result or organize data into a temporary table
- Consider rewriting the query using
NOT EXISTSorLEFT JOIN ... IS NULL - Use EXPLAIN to analyze the execution plan and identify bottlenecks
Q5. How can I exclude based on multiple columns?
A.
Since NOT IN is designed for single-column use, use NOT EXISTS or LEFT JOIN when you need composite exclusion across multiple columns. Combine multiple column conditions within the subquery.
Q6. What should I be careful about when the subquery returns many rows?
A.
When a subquery returns a large number of rows, NOT IN may suffer from performance degradation. Use indexing, temporary tables, or restructure the query to keep the subquery as small as possible.
Q7. If I am not getting the expected results, what should I check?
A.
- Verify that no NULL values are unintentionally included
- Run the subquery independently to confirm its results
- Check for mistakes in WHERE conditions or JOIN logic
- Review MySQL version-specific behavior and official documentation if necessary
8. Conclusion
The MySQL NOT IN clause is a highly useful construct for efficiently retrieving data that does not meet specific conditions. From simple exclusion lists to flexible filtering with subqueries, it can be applied in many practical scenarios.
However, there are important considerations in real-world usage, such as handling NULL values and performance degradation in large datasets. Issues like unexpected zero-result queries due to NULL values or slow execution caused by large subqueries require attention from both beginners and experienced developers.
By also understanding alternative approaches such as NOT EXISTS and LEFT JOIN ... IS NULL, you can write safer and more efficient SQL queries. Always select the most appropriate method based on your objectives and data scale.
Key Takeaways
NOT INis effective for simple exclusion conditions- Always guard against NULL values (make
IS NOT NULLa habit) - If performance is a concern, consider indexing strategies or using
NOT EXISTSand JOIN alternatives - Always verify effectiveness using the execution plan (EXPLAIN)
Avoid SQL “pitfalls” and practice smart data extraction by applying the concepts covered in this article to your daily work and learning.


