Venn diagrams are misleading for the purpose. a_horse provided the perfect clue in his comment:
Venn diagrams do not visualize joins, but set operations like union, intersect or except.
And his link to illustrate:
The example SQL is misleading on top of that. It starts with:
SELECT * FROM ...
That gets all columns from all joined tables. Not the expressed objective:
all organizations I'm either moderator or administrator.
UNION
Lennart offered a valid translation into SQL. Here's a shorter, more efficient one. The core query is:
SELECT organization FROM admin_organization WHERE user = 10
UNION
SELECT organization FROM moderator_organization WHERE user = 10
UNION
. Not JOIN
. And not UNION ALL
- we don't want duplicate organizations in the result.
The column name organization
is also misleading (IMHO). Should really be something like organization_id
for clarity.
The resulting set of unique IDs may already be all that's needed. To flesh it out with more (or all) attributes of the organization (columns of table organization
), now you JOIN
to the table:
SELECT *
FROM (
SELECT organization AS id FROM admin_organization WHERE user = 10
UNION
SELECT organization FROM moderator_organization WHERE user = 10
) x
JOIN organization USING (id);
It's typically (substantially) cheaper to apply UNION
on just the ID column, and then join. It may even be a necessity, if some of the columns have types have data types with no equality operator. More common than one might think. See:
Assuming referential integrity, enforced with FK constraints, nothing is lost in the join.
For convenience, it added a column alias in the subquery (organization AS id
), so that we can use the simplified join condition with USING (id)
which, in turn, allows us to use the simple (and now correct) SELECT *
in the outer query to get all columns of the table organization
without a duplicate ID column.
Alternative with EXISTS
Shorter equivalent that also avoids duplicating rows:
SELECT *
FROM organization o
WHERE EXISTS (SELECT FROM admin_organization WHERE user = 10 AND organization = o.id)
OR EXISTS (SELECT FROM moderator_organization WHERE user = 10 AND organization = o.id);
Naming convention
A naming convention with descriptive names can avoid some of the confusion and noise. Use organization_id
(or org_id
if you prefer short names and there is no ambiguity) for all three: admin_organization.organization
, moderator_organization.organization
, and organization.id
.