sqlcmd.net validated sql reference
intermediate joining MySQL MariaDB SQL Server PostgreSQL SQLite

Filter LEFT JOIN Matches In The ON Clause

Put right-table filters in the `ON` clause when you want to keep unmatched left-side rows.

Docker-validated Not currently validation-green

Keep every customer while only matching paid orders

Alice has a paid order, so her amount matches normally. Bob has an order, but it is not paid, so the ON filter prevents that row from matching and leaves paid_total as NULL. Carol has no orders at all and is still preserved. If o.status = 'paid' were moved to WHERE, Bob and Carol would disappear.

Rows loaded before the example query runs.
Setup
CREATE TABLE customers (id INT, name VARCHAR(50));

CREATE TABLE orders (
  id INT,
  customer_id INT,
  status VARCHAR(20),
  total INT
);

INSERT INTO
  customers (id, name)
VALUES
  (1, 'Alice'),
  (2, 'Bob'),
  (3, 'Carol');

INSERT INTO
  orders (id, customer_id, status, total)
VALUES
  (1, 1, 'paid', 100),
  (2, 2, 'pending', 75);
Shared across supported engines.
SQL
SELECT
  c.name,
  o.total AS paid_total
FROM
  customers c
  LEFT JOIN orders o ON c.id = o.customer_id
  AND o.status = 'paid'
ORDER BY
  c.id;
Returned rows for the shared example.
namepaid_total
Alice100
BobNULL
CarolNULL

The key behavior is that Bob and Carol are preserved even though they have no paid match.

Where this command helps.

  • keeping all parent rows while filtering optional related rows
  • avoiding accidental inner-join behavior in reports

What the command is doing.

A common LEFT JOIN bug is placing a right-table filter in WHERE instead of ON. That turns unmatched rows into filtered-out rows, which makes the query behave like an inner join. If you want to keep all rows from the left table and only restrict which right-side matches qualify, keep that condition inside the join predicate.