Driver FixRecommendedSound, Wi-Fi or graphics acting up? Check drivers firstFind missing or outdated drivers fast.Check DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
World desk5 min

SQL Joins Explained: A Beekeeping Co-op in Six Queries

Six fictional beekeeping co-op queries show how SQL joins combine related rows—and which unmatched records each join keeps.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A SQL join combines rows from related tables; the right join depends on which unmatched records you need to keep. An INNER JOIN keeps matching pairs, while a LEFT JOIN keeps every row from its left-hand table and fills right-hand columns with NULL when there is no match. The six queries below use a fictional beekeeping co-op to show how that choice changes the result.

How to read the example

Suppose the co-op tracks members and the apiaries they manage. A member can have no apiary or one apiary in this small example; an apiary may be assigned to a member or be awaiting assignment.

Each table has an identifier that uniquely names one record: members.member_id identifies a member, and apiaries.apiary_id identifies an apiary. The apiaries.member_id column refers to a member’s identifier. Such a reference is a foreign key; the column it points to is a key. The join condition connects those related columns.

members apiaries
member_id member_name apiary_id member_id
1 Ada 101 1
2 Ben 102 3
3 Cy 103 NULL
4 Dee

For clarity, the apiaries also have names: 101 is Clover Hill, 102 is North Field, and 103 is Meadow Lot. In this data, Ada’s apiary is assigned to member 1, North Field is assigned to member 3, Meadow Lot has no assigned member, and Ben and Dee have no apiary. The examples use explicit JOIN ... ON syntax, which makes the matching rule visible separately from any later filtering. Qualifying columns with table names or aliases also helps prevent ambiguous references. See the PostgreSQL tutorial on joins between tables and Microsoft Learn’s SQL Server joins documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

1. INNER JOIN: show only members with an apiary

SELECT m.member_name, a.apiary_name
FROM members AS m
INNER JOIN apiaries AS a
  ON a.member_id = m.member_id;

The condition pairs records whose member identifiers match. This returns Ada with Clover Hill and Cy with North Field: two rows. Ben and Dee are omitted because they have no matching apiary, and Meadow Lot is omitted because no member is assigned to it.

2. LEFT JOIN: keep every member

SELECT m.member_name, a.apiary_name
FROM members AS m
LEFT JOIN apiaries AS a
  ON a.member_id = m.member_id;

A LEFT JOIN preserves every row from its left input, here members. The result has four rows: Ada and Cy have matching apiary names, while Ben and Dee appear with NULL for apiary_name. The unassigned Meadow Lot still does not appear because it is on the right side.

3. RIGHT JOIN: keep every apiary

SELECT m.member_name, a.apiary_name
FROM members AS m
RIGHT JOIN apiaries AS a
  ON a.member_id = m.member_id;

A RIGHT JOIN preserves every row from the right input, apiaries. It returns three rows: Clover Hill with Ada, North Field with Cy, and Meadow Lot with NULL for the member name. Ben and Dee do not appear because they are unmatched rows on the left.

You can express the same preservation with a left join by reversing the table order:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
SELECT m.member_name, a.apiary_name
FROM apiaries AS a
LEFT JOIN members AS m
  ON m.member_id = a.member_id;

4. FULL JOIN: keep unmatched rows from both tables

SELECT m.member_name, a.apiary_name
FROM members AS m
FULL JOIN apiaries AS a
  ON a.member_id = m.member_id;

A FULL JOIN preserves matching pairs plus unmatched rows from both inputs. This result has five rows: two matched pairs, Ben and Dee with no apiary, and Meadow Lot with no member. Where one side has no match, its columns are NULL.

5. CROSS JOIN: deliberately pair every member with every apiary

SELECT m.member_name, a.apiary_name
FROM members AS m
CROSS JOIN apiaries AS a;

A CROSS JOIN has no matching condition: it produces every possible combination. With four members and three apiaries, this returns 12 rows (4 × 3). That can be useful when every combination is intended, such as building a complete member-by-apiary planning grid; it is usually not the right substitute for a relationship-based join.

6. Self-join: compare members in the same table

A join can relate a table to itself. For example, pair each member with members whose identifier is higher, so each two-member combination appears once:

SELECT m1.member_name AS first_member,
       m2.member_name AS second_member
FROM members AS m1
INNER JOIN members AS m2
  ON m1.member_id < m2.member_id;

The aliases m1 and m2 let the query refer to the two roles separately. With four members, the condition returns six pairs: Ada–Ben, Ada–Cy, Ada–Dee, Ben–Cy, Ben–Dee, and Cy–Dee. The condition is deliberately different from the equality condition used to connect members to apiaries.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Choose a join by the rows you must retain

Join Rows preserved Result in this example
INNER JOIN Only matching pairs 2 member–apiary pairs
LEFT JOIN Every left-side row, matched or not 4 member rows
RIGHT JOIN Every right-side row, matched or not 3 apiary rows
FULL JOIN Every row from both sides, matched where possible 5 total rows
CROSS JOIN Every possible row combination 12 combinations

These are the documented join behaviors in PostgreSQL 18’s table expressions documentation; consult the documentation for your database when checking dialect-specific syntax and behavior.

Keep join conditions and filters distinct

ON states how rows match. You can also write USING (member_id) when the intended join columns share a name, as they do here; it is a concise alternative for this simple relationship. Avoid using NATURAL JOIN casually: it infers matches from every same-named column, so adding a same-named column later can silently change the join condition. PostgreSQL documents both forms and that schema sensitivity in its table expressions reference.

Be especially deliberate about filters after an outer join. For example, to keep every member but include only apiary matches whose name is Clover Hill, put the restriction in ON:

SELECT m.member_name, a.apiary_name
FROM members AS m
LEFT JOIN apiaries AS a
  ON a.member_id = m.member_id
 AND a.apiary_name = 'Clover Hill';

This still returns all four members; only Ada has a matching apiary name, and the other right-side values are NULL. If instead you put a.apiary_name = 'Clover Hill' in WHERE, rows with NULL apiary names fail that condition, so the result no longer keeps members without that match. Put a restriction in WHERE when you mean to filter the completed result; put it in ON when it should limit matches without discarding left-side rows.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

What a join means for execution

It is useful to imagine a join checking candidate row pairs against its condition, but that is a conceptual model, not a claim about how the database physically executes every query. PostgreSQL notes that actual execution is usually more efficient than a literal pair-by-pair process. SQL Server documentation describes the optimizer choosing physical join algorithms and join order based on factors such as table size, indexes, and data distribution. Therefore, choose join syntax for the result you need rather than assuming one written form guarantees a particular execution strategy. See the PostgreSQL joins tutorial and SQL Server joins reference.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.