The not equal operator, written <> or !=, is true when two values are different. Put it in a WHERE clause to leave out the rows that match a value. The examples work in PostgreSQL, MySQL, SQLite and SQL Server.
How to use not equal
Put <> or != between two values. They mean exactly the same thing. <> is the SQL standard spelling, and != is the one most programming languages use.
value1 <> value2
value1 != value2
SELECT 5 <> 3;
-- Output: true
SELECT 'apple' != 'apple';
-- Output: false
SELECT NULL <> 3;
-- Output: NULL
-- MySQL and SQLite show true and false as 1 and 0. SQL Server can't
-- select a comparison like this: use it in a WHERE clause there.
In a query, not equal goes in the WHERE clause and keeps every row whose value is different:
-- Input: tickets
-- id | subject | status
-- ---+-----------------------+--------
-- 1 | Login fails on Safari | open
-- 2 | Typo on pricing page | closed
-- 3 | Export times out | pending
-- 4 | Add a dark theme | NULL
SELECT id, subject, status
FROM tickets
WHERE status <> 'closed';
-- Output:
-- id | subject | status
-- ---+-----------------------+--------
-- 1 | Login fails on Safari | open
-- 3 | Export times out | pending
Ticket 4 isn’t in the result, even though its status isn’t 'closed'. That’s the first rule below.
Rules to know
-
Not equal never matches NULL. Comparing NULL with anything gives NULL (unknown) rather than true, so the
WHEREclause drops the row. AddOR column IS NULLto keep rows that have no value:
-- Input: the tickets table above
SELECT id, subject, status
FROM tickets
WHERE status <> 'closed' OR status IS NULL;
-- Output:
-- id | subject | status
-- ---+-----------------------+--------
-- 1 | Login fails on Safari | open
-- 3 | Export times out | pending
-- 4 | Add a dark theme | NULL
-
A NULL in a
NOT INlist removes every row.status NOT IN ('closed', 'pending')is shorthand forstatus <> 'closed' AND status <> 'pending', so a single NULL in the list makes the whole condition unknown. Watch for this when the list comes from a subquery on a column that allows NULLs:
-- Input: the tickets table above
SELECT id, status FROM tickets WHERE status NOT IN ('closed', 'pending');
-- Output:
-- id | status
-- ---+-------
-- 1 | open
SELECT id, status FROM tickets WHERE status NOT IN ('closed', NULL);
-- Output:
-- id | status
-- ---+-------
-- (0 rows)
-
MySQL and SQL Server ignore case by default, so there
'Apple' <> 'apple'is false. -
Ask for what you want when you can.
status <> 'closed'also matches any status someone adds later, and because it usually matches most of the table, the database rarely gets any help from an index. If you mean “open or pending”,status IN ('open', 'pending')says so.
Alternative syntax
NOT (status = 'closed') is another way to write status <> 'closed', and it skips NULLs in the same way.
To compare without the NULL surprise, use IS DISTINCT FROM, a NULL-safe not equal that treats NULL as a value of its own (SQL Server added it in 2022, SQLite in 3.39):
-- Input: the tickets table above
SELECT id, status FROM tickets WHERE status IS DISTINCT FROM 'closed';
-- Output:
-- id | status
-- ---+--------
-- 1 | open
-- 3 | pending
-- 4 | NULL
-- MySQL has no IS DISTINCT FROM. Use its NULL-safe <=> instead:
SELECT id, status FROM tickets WHERE NOT (status <=> 'closed');
When should you use not equal?
Use not equal when a query should skip the rows that have one particular value. Most uses fall into one of these five.
Filter out one status or category
Cancelled orders, void invoices, a category you don’t stock: <> leaves out the rows with that value and keeps everything else.
Skip one specific record
Compare an id to leave out one row or group: the article someone is reading when you list related ones, the signed-in user in a list of other members, or one department in a company report. Numbers don’t need quotes.
Narrow results with other conditions
Combine <> with AND and OR to exclude a value while filtering on other columns, such as orders that aren’t cancelled and are over a certain amount. To exclude several values of the same column, use NOT IN.
Find rows where two columns differ
Not equal works between two columns too. Compare an old value with a new one, a counted quantity with the figure on record, or a shipping address with a billing address.
Keep rows where the value is missing
Because <> skips NULLs, decide whether rows with no value belong in the result. Add OR column IS NULL to keep them, or use the NULL-safe syntax above.
Real examples of not equal
Total the invoices that count
Void invoices shouldn’t count toward revenue:
-- Input: invoices
-- invoice_id | customer | status | amount
-- -----------+------------+--------+--------
-- 1001 | Acme Corp | paid | 1200.00
-- 1002 | Birch & Co | void | 450.00
-- 1003 | Acme Corp | open | 300.00
-- 1004 | Cobalt Ltd | paid | 875.50
SELECT SUM(amount) AS invoiced
FROM invoices
WHERE status <> 'void';
-- Output: 2375.50
List related articles, minus the one being read
A reader is on article 2. Show the other articles on the same topic:
-- Input: articles
-- id | title | topic
-- ---+----------------------+-------
-- 1 | Indexing basics | SQL
-- 2 | Your first JOIN | SQL
-- 3 | Docker for beginners | DevOps
-- 4 | Window functions | SQL
SELECT id, title
FROM articles
WHERE topic = 'SQL'
AND id <> 2;
-- Output:
-- id | title
-- ---+-----------------
-- 1 | Indexing basics
-- 4 | Window functions
Show only products you can sell
Leave out discontinued products, products with no price set, and products that are out of stock:
-- Input: products
-- product_name | category | price | stock_quantity
-- ---------------+--------------+-------+---------------
-- Desk Organizer | Office | 18.50 | 40
-- Fax Machine | Discontinued | 89.00 | 3
-- Gift Wrap | Seasonal | 0.00 | 120
-- Trail Backpack | Outdoors | 64.00 | 0
-- Water Bottle | Outdoors | 12.99 | 75
SELECT product_name, category, price
FROM products
WHERE category <> 'Discontinued'
AND price > 0
AND stock_quantity <> 0;
-- Output:
-- product_name | category | price
-- ---------------+----------+------
-- Desk Organizer | Office | 18.50
-- Water Bottle | Outdoors | 12.99
Find the fields that actually changed
An audit log records every save, including saves that didn’t change anything. Compare the two columns to keep only real changes:
-- Input: audit_log
-- log_id | field_name | old_value | new_value
-- -------+------------+-------------+------------
-- 1 | email | dan@old.com | dan@new.com
-- 2 | city | Austin | Austin
-- 3 | plan | free | pro
SELECT log_id, field_name, old_value, new_value
FROM audit_log
WHERE old_value <> new_value;
-- Output:
-- log_id | field_name | old_value | new_value
-- -------+------------+-------------+------------
-- 1 | email | dan@old.com | dan@new.com
-- 3 | plan | free | pro
If either column can be NULL, use IS DISTINCT FROM (or NOT (old_value <=> new_value) in MySQL), or a value set for the first time won’t count as a change.
Remind everyone who hasn’t said yes
Guests who haven’t replied have a NULL rsvp, and they need the reminder most:
-- Input: invitations
-- guest | email | rsvp
-- ------------+------------------+------
-- Ines Moreau | ines@example.com | yes
-- Raj Patel | raj@example.com | no
-- Hana Sato | hana@example.com | NULL
-- Leo Grant | leo@example.com | maybe
SELECT guest, email, rsvp
FROM invitations
WHERE rsvp <> 'yes' OR rsvp IS NULL;
-- Output:
-- guest | email | rsvp
-- ----------+------------------+------
-- Raj Patel | raj@example.com | no
-- Hana Sato | hana@example.com | NULL
-- Leo Grant | leo@example.com | maybe
Further reading about not equal
On this blog:
- SQL COALESCE guide: replace NULLs with a value before you compare
-
SQL LIKE guide:
NOT LIKEfor leaving out text that matches a pattern - SQL CASE statement guide: use comparisons to choose a value
- Having vs Where in SQL: where a filter goes when you group rows
- Comparing two values in PostgreSQL: the other comparison operators
Official documentation:
- PostgreSQL: Comparison operators
- MySQL:
<>and!= - SQLite: Operators
-
SQL Server:
<>,!=and IS DISTINCT FROM
Beekeeper Studio Is A Free & Open Source Database GUI
Best SQL query & editor tool I have ever used. It provides everything I need to manage my database. - ⭐⭐⭐⭐⭐ Mit
Beekeeper Studio is fast, intuitive, and easy to use. Beekeeper supports loads of databases, and works great on Windows, Mac and Linux.
What Users Say About Beekeeper Studio
"Beekeeper Studio completely replaced my old SQL workflow. It's fast, intuitive, and makes database work enjoyable again."
"I've tried many database GUIs, but Beekeeper strikes the perfect balance between features and simplicity. It just works."