Building on onedaywhen's answer:
Yes, the lack of a set difference operator does hurt. It should totally be allowed. However, we can express set difference with set complement and intersection:
B - A = B ∩ A'
i.e. the difference of B and A is in fact B's intersection with A's complement. We have the intersection as an allowed operator, and while a relation's proper complement is an ugly thing, the complement of an R1 ⊆ R relative to R (i.e. the stuff in R that aren't in R1) can be found easily with a join:
SELECT DISTINCT R0.x
FROM R as R1
JOIN R as R0 ON R1.x<>R0.x
WHERE R1.x=val
is the complement relative to R of
SELECT DISTINCT R.x FROM R WHERE R.x=val
So, here comes a solution to the riddle, I think: it's easy to get all the boats reserved by two or more guys: select all the boats that are in the reserves table, take the cartesian product of the result with itself, then select each row that has different sailor1 and sailor2. In the unwieldy relational algebra notation they taught me:
π( R.bid ) (
σ( R.bid=R2.bid and R.sid<R2.sid )( R x ρ(R, R2) )
)
(where π is the projection operator, σ is the selection operator, and ρ is the rename operator)
This nets the id's of all the boats reserved by two or more people. Now I'm going to get all the boats that were reserved by two or less guys. To do this, I'll select all the boats reserved by three or more guys, and take the set's complement by selecting all the rows from the original table which aren't present in that set. It won't be pretty, but here it goes:
π(R.bid)(σ(R.bid<>R1.bid)(
π(R.bid)(R)
x
π(R1.bid) (
σ( R1.bid=R2.bid and R2.bid=R3.bid and R1.sid<R2.sid and R2.sid<R3.sid )( ρ(R, R1) x ρ(R, R2) x ρ(R, R3) )
)
))
You see, I select all the rows which have the property, then select all the rows from the original table which aren't these, netting us all the rows which don't have the property, here meaning all the boats not reserved by three or more people, the boats reserved by two or less persons.
To get the boats with exactly two guys reserving them, simply intersect this with the set of boats reserved by more than one guy.
π( R.bid ) (
σ( R.bid=R2.bid and R.sid<R2.sid )( R x ρ(R, R2) )
) ∩ π( R.bid ) (
σ(R.bid<>R1.bid)(
π(R.bid)(R)
x
π(R1.bid) (
σ( R1.bid=R2.bid and R2.bid=R3.bid and R1.sid<R2.sid and R2.sid<R3.sid )( ρ(R, R1) x ρ(R, R2) x ρ(R, R3) )
)
)
)
Ugh. It's so ugly it hurts. I wish I knew a nicer notation.
SQLishly, it might look like this, I think:
(SELECT DISTINCT R1.bid
FROM Reserves AS R1
JOIN Reserves AS R2 ON R1.bid = R2.bid AND R1.sid < R2.sid
) INTERSECT (
SELECT DISTINCT R.bid
FROM Reserves AS R1
JOIN Reserves AS R2 ON R1.bid = R2.bid AND R1.sid < R2.sid
JOIN Reserves AS R3 ON R1.bid = R3.bid AND R2.sid < R3.sid
JOIN Reserves AS R ON R.bid<>R1.bid
)
Please note that this is exactly onedaywhen's solution, except I expressed set difference as taking the intersection with the complement.