3 回答
you said σ(COUNT(Car)=3)(R), but COUNT is an aggregation function.
without aggregations, the only way I see is loop through the R table rows by row counting Owner. Something like:
for each row
If owner=previous_owner then n_cars++
else (if n_cars>=3 then return owner
end
\pi_{Car.owner}(\sigma_{Car.owner = C1.owner\wedge
C1.owner = C2.owner\wedge
Car.vin != C1.vin\wedge
C1.vin != C2.vin\wedge
Car.vin != C2.vin}(Car x
\rho_{C1}(Car) x
\rho_{C2}(Car)))
-
\pi_{Car.owner}(\sigma_{Car.owner = C1.owner\wedge
C1.owner = C2.owner\wedge
C2.owner = C3.owner \wedge
Car.vin != C1.vin\wedge
C1.vin != C2.vin\wedge
Car.vin != C2.vin \wedge
Car.vin != C3.vin\wedge
C1.vin != C3.vin\wedge
C2.vin != C3.vin}(Car x
\rho_{C1}(Car) x
\rho_{C2}(Car) x
\rho_{C3}(Car)))
where \pi
is projection, \sigma
is selection, x
is cartesian product, \rho
is renaming, \wedge
represents conjunction and I assume the attributes of relation Car to be called owner
and vin
.
Here's one way of doing it, in SQL using operators that are easy to translate to relational algebra, and using slightly different test data (different types, same names):
WITH R
AS
(
SELECT *
FROM (
VALUES (1, 1),
(2, 2), (2, 3),
(3, 1), (3, 2), (3, 3),
(4, 1), (4, 2), (4, 3), (4, 4)
) AS T (Owner, Car)
),
OwnersWithAtLeastThreeCars
AS
(
SELECT DISTINCT R1.Owner
FROM R AS R1, R AS R2, R AS R3
WHERE R1.Owner = R2.Owner
AND R2.Owner = R3.Owner
AND R1.Car <> R2.Car
AND R1.Car <> R3.Car
AND R2.Car <> R3.Car
),
OwnersWithAtLeastFourCars
AS
(
SELECT DISTINCT R1.Owner
FROM R AS R1, R AS R2, R AS R3, R AS R4
WHERE R1.Owner = R2.Owner
AND R2.Owner = R3.Owner
AND R3.Owner = R4.Owner
AND R1.Car <> R2.Car
AND R1.Car <> R3.Car
AND R1.Car <> R4.Car
AND R2.Car <> R3.Car
AND R2.Car <> R4.Car
AND R3.Car <> R4.Car
)
SELECT * FROM OwnersWithAtLeastThreeCars
EXCEPT
SELECT * FROM OwnersWithAtLeastFourCars;
p.s. I'm using 'old style' (i.e. pre-1992) standard SQL joins, which are widely condemned on Stackoverflow. I'm using them not only because it fits with the OP's list of available operators but, frankly, in these circumstances I find them much easier to write than using infix INNER JOIN
notation.