October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk4 min

The NOT IN Trap: Why Your SQL Query Returns Zero Rows

A NULL in the results of a NOT IN subquery can turn nonmatching comparisons into UNKNOWN. Learn when to filter NULLs, when NOT EXISTS fits, and how outer NULL keys change the result.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A single NULL returned by a NOT IN subquery can make otherwise nonmatching rows fail the WHERE filter. SQL comparisons with NULL can be UNKNOWN, and WHERE keeps only rows whose condition is TRUE. Filter unknown values out of the comparison set, or use NOT EXISTS when the rule you mean is “no matching row exists.”

How one NULL can make NOT IN return no rows

Consider a customers table and an orders table. If even one orders.customer_id is NULL, this query can return no customers, even if many customer IDs have no matching order:

SELECT c.customer_id
FROM customers AS c
WHERE c.customer_id NOT IN (
  SELECT o.customer_id
  FROM orders AS o
);

x NOT IN (SELECT y ...) means that x must be unequal to every value the subquery returns. If one returned value is NULL, the comparison against it can be UNKNOWN, not TRUE. A nonmatching customer therefore does not satisfy the predicate as true, so the WHERE clause removes that row. An actual equal value makes the exclusion false; a right-side NULL is especially troublesome for values that have no equal match.

PostgreSQL 18 documents that NOT IN yields null when the left expression is null, or when there is no equal right-side value and at least one right-side row is null: PostgreSQL: Subquery Expressions. Microsoft likewise explains that comparisons involving null can return UNKNOWN, and recommends IS NULL or IS NOT NULL to test for nullness: Microsoft Learn: NULL and UNKNOWN (Transact-SQL).

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose a fix based on what NULL means

Filter NULLs out of the exclusion set

Use this when the intended comparison set is made up only of known customer IDs. An unknown order customer ID is not a known ID to exclude:

SELECT c.customer_id
FROM customers AS c
WHERE c.customer_id NOT IN (
  SELECT o.customer_id
  FROM orders AS o
  WHERE o.customer_id IS NOT NULL
);

This preserves NOT IN while ensuring the subquery does not supply a null comparison value. It does not by itself decide what to do with a null c.customer_id; handle that outer-side case explicitly if such rows are possible.

Use NOT EXISTS when the rule is absence of a match

If the business question is whether any order row has the same known customer ID, write that rule directly as a correlated subquery:

SELECT c.customer_id
FROM customers AS c
WHERE NOT EXISTS (
  SELECT 1
  FROM orders AS o
  WHERE o.customer_id = c.customer_id
);

An unrelated null in orders.customer_id does not poison this predicate: it does not make the equality true, so it does not count as a matching row. But if c.customer_id is null, the equality is not true for any order row; NOT EXISTS can therefore include that customer. Add AND c.customer_id IS NOT NULL if unknown customer IDs should be excluded. If they should be included or reported separately, express that policy deliberately instead.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Check both sides of the comparison

A null in the subquery result and a null in the outer key are distinct cases. Filtering nulls on the right prevents them from making nonmatching NOT IN comparisons unknown. It does not make a null outer key into a known value. With a nonempty right-hand set, NULL NOT IN (...) is not true; a NOT EXISTS equality check, by contrast, may find no true match and include that outer row.

Decide how unknown keys should be handled before choosing the query:

  • Exclude unknown outer keys: add an explicit IS NOT NULL condition for the outer key.
  • Include them as having no known match: use the correlated NOT EXISTS logic, understanding that null keys do not match through ordinary equality.
  • Report them separately: query them with IS NULL rather than treating an unknown key as an ordinary unmatched ID.

Account for empty sets and SQL dialect differences

Do not assume every database handles every edge case or syntax identically. SQLite’s expression documentation gives an IN/NOT IN result matrix and notes that NOT IN against an empty right-hand set is true even when the left expression is null: SQLite: Expressions. Empty-list syntax and other dialect details can also vary. Name and test against the database engine and version you actually use.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Compare the two patterns against your intended rule

Question NOT IN with a NULL filter Correlated NOT EXISTS
Can a null on the subquery side affect the result? Not after the subquery filters it with IS NOT NULL. An unrelated null does not count as a matching row under ordinary equality.
What happens if the outer key is null? With a nonempty comparison set, the predicate is not true; add explicit handling if needed. The equality is not true for any row, so the outer row can be included.
Best fit for the intended rule Exclude values absent from a set of known, non-null keys. Keep rows for which no row satisfying the match condition exists.
Engine behavior Verify dialect syntax and empty-set behavior. Verify dialect syntax and the intended null-key policy.

Neither form is a universal drop-in replacement for the other when null keys matter. If performance is also a concern, inspect the execution plan on the target database rather than assuming one pattern is faster.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.