Skip to content
JackSparrow414
Go back

Oracle IN and EXISTS: Query Notes

Table of contents

Open Table of contents

Article body

While reading SQL today, I came across EXISTS. When I first used it, I only knew that it served a similar purpose to IN: matching a condition against data from a subquery. Today I decided to understand the distinction. After looking it up, I learned more about their differences, including performance considerations, which surprised me.

Updated 2018-11-08:

The issue: after gaining a rough understanding of IN and EXISTS, I thought NOT IN would be suitable when the subquery returned little data. I overlooked an important detail, though: my subquery actually returned a large result set.

Important note: in Oracle, the number of values supplied to NOT IN cannot exceed 1,000, or SQL execution fails. So, friends, use EXISTS instead—a lesson learned the hard way.

I also learned more about how NULL affects IN and NOT IN subqueries.

Explanation of NULL effects on IN and NOT IN subquery results

Keep this in mind during development:

When filtering a field with a “not equal” condition, first determine whether the query should include NULL values.

Let’s start with EXISTS. It produces a Boolean result, and Oracle uses that true or false result to decide whether to retain a row. If true, the row is kept; if false, it is excluded.

With EXISTS, the main query—the part before EXISTS—is executed first. For example:

select t.name,t.sex from A t where t.dr = 0 and exists (select B.id from B where B.pk = B.pk);

PS: The query inside EXISTS must be correlated with the outer table for the intended filtering to work.

After obtaining the main query’s result set, the statement following EXISTS is evaluated for each row. Rows with a true result are kept, and those with a false result are excluded. The resulting set is returned.

Note: you cannot put a field name directly before EXISTS as you would with IN; doing so produces an invalid relational operator error, as shown below.

Oracle SQL reporting an invalid relational operator when a field name precedes EXISTS

Updated 2018-10-19: another reminder about writing the SQL inside EXISTS.

SQL example with an EXISTS subquery uncorrelated with the outer table

The form shown above does not perform the intended filtering. EXISTS must include a condition correlating the subquery with the outer table. The intended form is shown below.

EXISTS subquery correlated with the outer table by primary key, with filtered results

Perhaps I still haven’t fully understood how to use EXISTS.

With IN, the subquery—the part after IN—is executed first. For example:

select t.name,t.sex from A t where t.dr = 0 and m.id in (select * from B m where m.pk = t.pk);

The subquery produces a result set, which is combined with the main table as a Cartesian product. The filtering conditions then determine the final result set.

From this, my takeaway is to use EXISTS when the main query has more data to process, and IN when the subquery has more data to process.

Additional note:

IN uses a hash join algorithm to join tables during sorting.

EXISTS uses a loop algorithm to join tables during sorting.

I don’t yet understand exactly how these two algorithms work…

Here are a few database terms:

Press F5 in PL/SQL to display a SQL execution plan. You may see the following terms, as shown in these screenshots:

PL/SQL execution plan showing nested loops, table scans, and index scans

HASH JOIN, TABLE ACCESS, and INDEX FAST FULL SCAN in a PL/SQL execution plan


Share this post:

Previous Post
JavaScript Error Notes (Part 1)
Next Post
Everyday Development Pitfalls

Comments

Questions, corrections, and experiences are welcome. Sign in with GitHub to comment; both language versions share this discussion.

Comments are available on the live site only.