{"id":33813,"date":"2024-01-09T11:54:37","date_gmt":"2024-01-09T01:54:37","guid":{"rendered":"https:\/\/database.guide\/?p=33813"},"modified":"2024-01-09T11:54:38","modified_gmt":"2024-01-09T01:54:38","slug":"sql-exists-explained","status":"publish","type":"post","link":"https:\/\/database.guide\/sql-exists-explained\/","title":{"rendered":"SQL EXISTS Explained"},"content":{"rendered":"\n<p>The SQL <code>EXISTS<\/code> predicate is used to specify a test for a non-empty set. It returns <code>TRUE<\/code> or <code>FALSE<\/code>, depending on the outcome of the test. <\/p>\n\n\n\n<p>When we incorporate the <code>EXISTS<\/code> predicate operator into our SQL queries, we specify a subquery to test for the existence of rows. If there are any rows, then the subquery is <code>TRUE<\/code>. If there are no rows, then the subquery is <code>FALSE<\/code>.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Example<\/h2>\n\n\n\n<p>Here&#8217;s a quick example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT ArtistName \nFROM Artists ar\nWHERE EXISTS (\n    SELECT * FROM Albums al\n    WHERE al.ArtistId = ar.ArtistId\n    AND ReleaseDate &lt; '2000-01-01'\n);<\/code><\/pre>\n\n\n\n<p>Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">+-------------+\n| ArtistName  |\n+-------------+\n| Iron Maiden |\n| AC\/DC       |\n| Jim Reeves  |\n| Buddy Rich  |\n| Tom Jones   |\n+-------------+<\/pre>\n\n\n\n<p>Here, my query returns the names of all artists that released at least one album before the year 2000.<\/p>\n\n\n\n<p>The subquery returns all albums from each artist that have a <code>ReleaseDate<\/code> prior to <code>2000-01-01<\/code>. The outer query uses the SQL <code>EXISTS<\/code> operator to test for the existence of any rows that are returned by the subquery. Basically, we only get artists that have at least one row returned by the subquery. In this case, <code>EXISTS<\/code> returns <code>TRUE<\/code> and we get a row for that artist. <\/p>\n\n\n\n<p>The above query is the equivalent of the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT ArtistName \nFROM Artists ar\nWHERE ar.ArtistId IN (\n    SELECT ar.ArtistId FROM Albums al\n    WHERE al.ArtistId = ar.ArtistId\n    AND ReleaseDate &lt; '2000-01-01'\n);<\/code><\/pre>\n\n\n\n<p>Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">+-------------+\n| ArtistName  |\n+-------------+\n| Iron Maiden |\n| AC\/DC       |\n| Jim Reeves  |\n| Buddy Rich  |\n| Tom Jones   |\n+-------------+\n5 rows in set (0.00 sec)<\/pre>\n\n\n\n<p>The difference is that the second query uses the <a href=\"https:\/\/database.guide\/sql-in-operator-for-beginners\/\" data-type=\"post\" data-id=\"11733\">SQL <code>IN<\/code> predicate<\/a> instead of <code>EXISTS<\/code>. When we use <code>IN<\/code>, we specify a column name that should be returned by the subquery. When we use <code>EXISTS<\/code>, we don&#8217;t need to specify any such column.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A <code>NOT EXISTS<\/code> Example<\/h2>\n\n\n\n<p>We can use <code>NOT EXISTS<\/code> in order to return the opposite of <code>EXISTS<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT ArtistName \nFROM Artists ar\nWHERE NOT EXISTS (\n    SELECT * FROM Albums al\n    WHERE al.ArtistId = ar.ArtistId\n    AND ReleaseDate &lt; '2000-01-01'\n);<\/code><\/pre>\n\n\n\n<p>Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">+------------------------+\n| ArtistName             |\n+------------------------+\n| Allan Holdsworth       |\n| Devin Townsend         |\n| Maroon 5               |\n| The Script             |\n| Lit                    |\n| Black Sabbath          |\n| Michael Learns to Rock |\n| Carabao                |\n| Karnivool              |\n| Birds of Tokyo         |\n| Bodyjar                |\n+------------------------+\n11 rows in set (0.00 sec)<\/pre>\n\n\n\n<p>Note that this is not the same as changing the <a href=\"https:\/\/database.guide\/sql-less-than\/\" data-type=\"post\" data-id=\"11797\">less than sign<\/a> to a <a href=\"https:\/\/database.guide\/sql-greater-than-operator-for-beginners\/\" data-type=\"post\" data-id=\"11820\">greater than sign<\/a> in our subquery. Here&#8217;s what happens when we do that:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT ArtistName \nFROM Artists ar\nWHERE EXISTS (\n    SELECT * FROM Albums al\n    WHERE al.ArtistId = ar.ArtistId\n    AND ReleaseDate > '2000-01-01'\n);<\/code><\/pre>\n\n\n\n<p>Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">+------------------------+\n| ArtistName             |\n+------------------------+\n| Devin Townsend         |\n| The Script             |\n| Michael Learns to Rock |\n| Tom Jones              |\n| Allan Holdsworth       |\n+------------------------+\n5 rows in set (0.00 sec)<\/pre>\n\n\n\n<p>Only five rows are returned, compared to the 11 rows returned when using <code>NOT EXISTS<\/code>. <\/p>\n\n\n\n<p>The logic between these two examples is different:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>The first example (using <code>NOT EXISTS<\/code>) returns all artists that don&#8217;t have an album released prior to the year 2000. This could include artists that haven&#8217;t released any albums at any time.<\/li>\n\n\n\n<li>The second example requires that the artist has released at least one album after the given date. This therefore excludes any artists who haven&#8217;t released any albums after that date, as well as artists that haven&#8217;t released any albums at all.<\/li>\n<\/ul>\n\n\n\n<p>Oh in case you&#8217;re wondering, my database is just a sample database, and it in no way represents a complete list of the actual albums released by those artists. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The Purpose of the Subquery<\/h2>\n\n\n\n<p>When using the <code>EXISTS<\/code> operator, the purpose of the subquery is merely to return at least one row, or none at all. The contents of the subquery is not normally important. And the number of rows returned by the subquery is not important. What is important is whether at least one row is returned or not &#8211; regardless of its contents.<\/p>\n\n\n\n<p>Because of the above, it&#8217;s unimportant which columns are included in the <code>SELECT<\/code> list. Therefore, in the above examples we could replace <code>SELECT *<\/code> with <code>SELECT al.ArtistId<\/code>, or even <code>SELECT 1<\/code> if we wanted. The result would be the same:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT ArtistName \nFROM Artists ar\nWHERE EXISTS (\n    SELECT 1 FROM Albums al\n    WHERE al.ArtistId = ar.ArtistId\n    AND ReleaseDate &lt; '2000-01-01'\n);<\/code><\/pre>\n\n\n\n<p>Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">+-------------+\n| ArtistName  |\n+-------------+\n| Iron Maiden |\n| AC\/DC       |\n| Jim Reeves  |\n| Buddy Rich  |\n| Tom Jones   |\n+-------------+<\/pre>\n\n\n\n<p>Also, it pays to bear in mind that the subquery may only be executed long enough to determine whether at least one row is returned, and not all the way to completion. In other words, the subquery may not necessarily return all rows that satisfy its criteria. Therefore, you may want to avoid using a subquery that relies on all rows being returned (such as a subquery that calls sequence functions, etc).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">SQL <code>IF EXISTS<\/code><\/h2>\n\n\n\n<p>Depending on your <a href=\"https:\/\/database.guide\/what-is-an-rdbms\/\" data-type=\"post\" data-id=\"222\">RDBMS<\/a>s you may be able to use the following <code>IF EXISTS<\/code> syntax to check whether an object exists before performing some action against it. <\/p>\n\n\n\n<p>Here&#8217;s an example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>IF EXISTS \n  (SELECT object_id FROM sys.tables\n  WHERE name = 'Artists'\n  AND SCHEMA_NAME(schema_id) = 'dbo')\n  PRINT 'The table exists'\nELSE \n  PRINT 'The table does not exist';<\/code><\/pre>\n\n\n\n<p>Result:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">The table exists<\/pre>\n\n\n\n<p>I ran this in SQL Server.<\/p>\n\n\n\n<p>The query could be modified to perform some other, more meaningful action. For example, it could drop a table only if it exists:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>IF EXISTS (\n    SELECT * FROM information_schema.tables\n    WHERE table_schema = 'dbo' AND table_name = 't1') \t\n    DROP TABLE dbo.t1;<\/code><\/pre>\n\n\n\n<p>We might want to do this in order to avoid any errors that might occur from trying to drop a table that doesn&#8217;t actually exist.<\/p>\n\n\n\n<p>However, many RDBMSs support the <code><a href=\"https:\/\/database.guide\/drop-table-if-exists-in-sql\/\" data-type=\"post\" data-id=\"33782\">DROP TABLE IF EXISTS<\/a><\/code> syntax, which is a more concise way to do it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">SQL <code>IF NOT EXISTS<\/code><\/h2>\n\n\n\n<p>Similar to the SQL <code>IF EXISTS<\/code> statement, we can negate it by using <code>NOT<\/code>. This can be handy if we want to create an object instead of drop it. For example, we could use <code>IF NOT EXISTS<\/code> to create a table only if it doesn&#8217;t already exist. This will help us avoid any errors that would occur from trying to create a table with the same name of an existing one.<\/p>\n\n\n\n<p>Example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>IF NOT EXISTS (\n    SELECT * FROM sys.tables t \n    JOIN sys.schemas s ON (t.schema_id = s.schema_id) \n    WHERE s.name = 'dbo' AND t.name = 't1') \t\n    CREATE TABLE dbo.t1 (\n        c1 int,\n        c2 varchar(10)\n        );<\/code><\/pre>\n\n\n\n<p>Here, the subquery checks the <code>sys.tables<\/code> view for the existence of a table of the given name (<code>t1<\/code>) under the schema of the given name (<code>dbo<\/code>). We could alternatively check the <code>information_schema.tables<\/code> view, or other views\/tables that the RDBMS uses for its metadata. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\">SQL <code>CREATE ... IF NOT EXISTS<\/code><\/h2>\n\n\n\n<p>Many RDBMSs support the <code>IF NOT EXISTS<\/code> syntax when creating objects, such as tables. This saves us from having to write out more complex code like in the previous example. Here&#8217;s how we can replace the previous example using this syntax:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CREATE TABLE IF NOT EXISTS t1 (\n        c1 int,\n        c2 varchar(10)\n        );<\/code><\/pre>\n\n\n\n<p>This works in many RDBMSs, but not in SQL Server or Oracle pre-23c at the time of writing (Oracle introduced the <code>IF NOT EXISTS<\/code> syntax as a new feature in Oracle Database 23c).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">SQL <code>DROP ... IF EXISTS<\/code><\/h2>\n\n\n\n<p>Similarly, we can use <code>IF EXISTS<\/code> when dropping an object from the database:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>DROP TABLE IF EXISTS t1;<\/code><\/pre>\n\n\n\n<p>Again, this provides us with a more concise way of checking for the existence of the object before dropping it. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>The SQL EXISTS predicate is used to specify a test for a non-empty set. It returns TRUE or FALSE, depending on the outcome of the test. When we incorporate the EXISTS predicate operator into our SQL queries, we specify a subquery to test for the existence of rows. If there are any rows, then the &#8230; <a title=\"SQL EXISTS Explained\" class=\"read-more\" href=\"https:\/\/database.guide\/sql-exists-explained\/\" aria-label=\"Read more about SQL EXISTS Explained\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[85,20],"class_list":["post-33813","post","type-post","status-publish","format-standard","hentry","category-sql","tag-operators","tag-what-is"],"_links":{"self":[{"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/posts\/33813","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/comments?post=33813"}],"version-history":[{"count":5,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/posts\/33813\/revisions"}],"predecessor-version":[{"id":33990,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/posts\/33813\/revisions\/33990"}],"wp:attachment":[{"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/media?parent=33813"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/categories?post=33813"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/database.guide\/wp-json\/wp\/v2\/tags?post=33813"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}