SQLEXCEPT / MINUS

EXCEPT / MINUS

EXCEPT combines the results of two SELECT queries and returns only the rows that appear in the first result set but do not appear in the second. It is a set-difference operation — think "give me A, minus anything also found in B."

As with UNION and INTERSECT, both queries must return the same number of columns with compatible types, and the operation removes duplicate rows from the output.

Basic syntax

SQL
SELECT column1, column2 FROM table_a
EXCEPT
SELECT column1, column2 FROM table_b;
EXCEPT vs MINUS — same operation, different keyword

The set-difference operation is standard SQL, but Oracle uses a different keyword for historical reasons.

Database

Keyword

PostgreSQL

EXCEPT

SQL Server

EXCEPT

SQLite

EXCEPT

Oracle

MINUS

MySQL

Not natively supported in most versions (see below)

Note
EXCEPT and MINUS behave identically — they just spell the same idea differently depending on the database vendor. If you are writing portable SQL, check which keyword your target database expects.
Worked example

A common practical use is comparing two customer lists — for example, finding customers who exist in your CRM export but were never actually imported into the production database.

crm_customers and imported_customers

SQL
SELECT customer_email FROM crm_customers
EXCEPT
SELECT customer_email FROM imported_customers;

-- crm_customers: alice@example.com, bob@example.com, carol@example.com
-- imported_customers: bob@example.com, carol@example.com

-- Result: customers in the CRM export that were never imported
-- alice@example.com

-- Oracle equivalent
SELECT customer_email FROM crm_customers
MINUS
SELECT customer_email FROM imported_customers;
Rewriting EXCEPT without native support

SQL
-- Using NOT EXISTS (usually the best-performing rewrite)
SELECT customer_email FROM crm_customers AS a
WHERE NOT EXISTS (
  SELECT 1 FROM imported_customers AS b
  WHERE b.customer_email = a.customer_email
);

-- Using LEFT JOIN + IS NULL
SELECT a.customer_email
FROM crm_customers AS a
LEFT JOIN imported_customers AS b
  ON a.customer_email = b.customer_email
WHERE b.customer_email IS NULL;

-- Using NOT IN — works, but beware of NULLs in the subquery
-- (if imported_customers.customer_email can be NULL, NOT IN returns
-- no rows at all; NOT EXISTS does not have this problem)
SELECT customer_email FROM crm_customers
WHERE customer_email NOT IN (
  SELECT customer_email FROM imported_customers
);
MySQL lacks native EXCEPT in most versions
Most MySQL versions do not support EXCEPT (or MINUS) at all — only very recent MySQL 8.0 releases have added it. For broad MySQL compatibility, use the NOT EXISTS or LEFT JOIN … WHERE … IS NULL pattern shown above instead of relying on the EXCEPT keyword.
  • EXCEPT returns rows from the first query that are absent from the second.

  • MINUS is Oracle's name for the same operation.

  • Column count and compatible types must match across both queries.

  • Duplicates are removed automatically from the result.

  • On databases without native support, use NOT EXISTS or LEFT JOIN ... IS NULL.