February 4, 2015

The SQL EXISTS operator is mostly used to test whether a subquery returns rows. It returns TRUE if rows exists in the subquery and FALSE if they do not.

SQL Exists

The EXISTS condition is used in combination with a subquery.  It returns TRUE whenever the subquery returns one or more values.

In its simplest form the syntax for the SQL EXISTS condition is

WHERE EXISTS (sub query)

Suppose we need to return all sales orders written by salespeople with sales year to date greater than three million dollars.  To do so we can use the EXISTS clause as shown in this example:

SELECT SalesOrderID,
       RevisionNumber,
       OrderDate
FROM   Sales.SalesOrderHeader
WHERE  EXISTS (SELECT 1
               FROM   sales.SalesPerson
               WHERE  SalesYTD > 3000000
                      AND SalesOrderHeader.SalesPersonID 
                        = Sales.SalesPerson.BusinessEntityID)

When this SQL executes the following comparisons are made:

  1. The WHERE clause returns all records where the EXISTS clause is TRUE.
  2. The EXIST clause uses a correlated subquery. The outer query is correlated to the inner query by SalesPersonID.
  3. Only SalesPersons with SalesYTD greater than three million are included in the results.
  4. The EXISTS clause returns TRUE if one or more rows are returned by the subquery.

The EXISTS condition is a membership condition in the sense it only returns TRUE if a result is returned.

SQL NOT EXISTS

Conversely, if we want to test for non-membership we can use NOT EXISTS.

NOT EXISTS returns TRUE if zero rows are returned.  So, if we want to find all sales orders that were written by salespeople that didn’t have 3,000,000 in year-to-date sales, we can use the following query:

SELECT SalesOrderID,
       RevisionNumber,
       OrderDate
FROM   Sales.SalesOrderHeader
WHERE  NOT EXISTS (SELECT 1
               FROM   sales.SalesPerson
               WHERE  SalesYTD > 3000000
                      AND SalesOrderHeader.SalesPersonID 
                        = Sales.SalesPerson.BusinessEntityID)

WHAT happens to NULL?

When the subquery returns a NULL what does EXIST return:  NULL, TRUE, or FALSE?

To be honest I was surprised.

I was sure it would return NULL, but to my surprise, I learned it returns TRUE.  Therefore, if your subquery returns a NULL value, the SQL EXISTS statement resolves to TRUE.  In the following example all the SalesOrderHeader rows are returned as the WHERE clause essentially resolved to TRUE:

SELECT SalesOrderID,
       RevisionNumber,
       OrderDate
FROM   Sales.SalesOrderHeader
WHERE  EXISTS (SELECT NULL)

As we study the IN operator, we’ll see this behavior is unique to the EXISTS clause.

Learn More

What to read next:

About the author 

Kris Wenzel

Kris Wenzel has been working with databases over the past 30 years as a developer, analyst, and DBA. He has a BSE in Computer Engineering from the University of Michigan and a MBA from the University of Notre Dame. Kris has written hundreds of blog articles and many online courses. He loves helping others learn SQL.

  • Hi Kris, I need to check a date column in a subquery for any nulls and return a boolean to use in the outer query. How would you do this? where would you place the subquery in the where, from, select? Any help would be greatly appreciated.

  • Hi Kris, suggestion…

    This format of compound elements in the where clause and sub-queries has been useful to me over the years. It’s rare to see it in documentation. If you decide to revise the blog post, think about including examples like this.

    SELECT
    table1.*
    FROM
    table1
    WHERE
    (field1, field2) in ( (1, 125788 ), (1, 127753), (1, 301852) )
    ;

    Of course, instead of specific values on the right side of the “in”, you can have a subquery that returns the same number of values.

  • Hello Kris

    Can you help me please?
    I have a subquery in the where clause which gives back the name of a column, but the SQL doesn’t recognize the result. So when I run the query it returns an empty table.

    The code looks like this:

    SELECT * FROM projects where (SELECT CONCAT(“`p_”,id,”`”) from properties where id in (select SUBSTRING_INDEX(SUBSTRING_INDEX(ids, ‘,’, numbers.n), ‘,’, -1) from (select 1 n union all select 2 union all select 3 union all select 4 union all select 5) numbers INNER JOIN filters_properties on CHAR_LENGTH(ids) -CHAR_LENGTH(REPLACE(ids, ‘,’, ”))>=numbers.n-1 WHERE filter_id = (SELECT id FROM filters WHERE name = ‘GYMS’))) = 1;

    Another problem: when the subquery returns more than 1 row, I don’t know what to do with it. How can I separate them to get a result like (p_1 = 1 or p_2 = 1 or p_3 = 1)?

  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

    Are YOU READY TO START LEARNING SQL SERVER, BUT DON'T KNOW WHERE TO START?

    Nothing is worse than, being excited to learn a new tool but not knowing where to start, wasting time learning the wrong features, and being overwhelmed .

    But it doesn't have to be this way.

    I'm Putting together a free email course to help you get started learning SQL Server.

    Name*
    Email*
    >