SELECT *
FROM reservation
WHERE id NOT IN (select reservation_id
FROM reservation_log
WHERE change_type = 'cancel')
OF:
SELECT r.*
FROM reservation r
LEFT JOIN reservation_log l ON r.id = l.reservation_id AND l.change_type = 'cancel'
WHERE l.id IS NULL
De eerste versie is intuïtiever, maar ik denk dat de tweede versie meestal betere prestaties levert (ervan uitgaande dat je indexen hebt op de kolommen die in de join worden gebruikt).
De tweede versie werkt omdat LEFT JOIN geeft een rij terug voor alle rijen in de eerste tabel. Wanneer de ON voorwaarde slaagt, bevatten die rijen de kolommen uit de tweede tabel, net als INNER JOIN . Als de voorwaarde faalt, bevat de geretourneerde rij NULL voor alle kolommen in de tweede tabel. De WHERE l.id IS NULL test komt dan overeen met die rijen, zodat het alle rijen vindt die geen overeenkomst hebben tussen de tabellen.