# CROSS JOIN solution for records “missing” from a link table

Use case: We have a simple two tables plus a link table setup using some modern RDBMS.

For example:

Hospital table (id, name, ...)

Physician table (id, name, ...)

Visiting_Privilege table (hospital_id, physician_id, ...)

Our goal is to find records that are "missing" (absent) from the link table.

Using our example: List physicians and hospitals where they are not authorized to see patients.

The proposed solution: Create a full Cartesian Product between the two main tables, JOIN it with the link table, filter records with either of the IDs as NULL.

SELECT p.name, h.name
FROM Physicians p
CROSS JOIN Hospitals h
LEFT OUTER JOIN Visiting_Privilege v ON p.id = v.physician_id AND h.id = v.hospital_id
WHERE v.physician_id IS NULL OR v.hospital_id IS NULL;


We assume that tables are properly indexed and the SQL engine provides reasonable query optimization.

1. Would it be a right way to attack the problem?

2. Is there a better solution that avoids the cost of a full Cartesian Product?

I am pretty sure that this is the right approach to solve this problem, but depending on the RDBMS, it is not necessary the use of any index to access each row. Oracle, for instance, will probably operate with Hash Joins in this case, because of the high cardinality of the query (at the end of this task all rows of this 3 tables must be accessed) and if you have an index on the link table, it will use an Index Fast Full Scan. I don't know if other RDBMS have the power of Hash Joins operations, which uses more memory instead of IOs.

Another syntax that could be used in this problem is the NOT EXISTS operator. Choose which syntax you think will translate more clearly the meaning of the query. In Oracle it will forces to perform an Hash Join Anti operation in the last table.

I tried to simulate the situation using SQLite3.

The following query gives me the same results as yours.

SELECT p.name, h.name FROM Physicians AS p
LEFT JOIN Hospitals AS h
ON h.id = v.hospital_id
LEFT JOIN Visiting_Privilege AS v
ON p.id = v.physician_id
WHERE hospital_id IS NULL;


I'm not sure which one performs better, though.