以 onedaywhen 的回答为基础:
是的,缺少集合差异运算符确实会造成伤害。应该完全允许。但是,我们可以用集补和交集来表示集差:
B - A = B ∩ A'
即B 和 A 的区别实际上是 B 与 A 的补码的交集。我们将交集作为允许的运算符,虽然关系的适当补码是一件丑陋的事情,但 R1 ⊆ R 相对于 R 的补码(即 R 中不存在于 R1 中的内容)可以通过连接轻松找到:
SELECT DISTINCT R0.x
FROM R as R1
JOIN R as R0 ON R1.x<>R0.x
WHERE R1.x=val
是相对于R的补码
SELECT DISTINCT R.x FROM R WHERE R.x=val
所以,这个谜题的解决方案来了:很容易得到两个或更多人保留的所有船:选择保留表中的所有船,将结果的笛卡尔积与自身相乘,然后选择具有不同水手1 和水手2 的每一行。在他们教给我的笨拙的关系代数符号中:
π( R.bid ) (
σ( R.bid=R2.bid and R.sid<R2.sid )( R x ρ(R, R2) )
)
(其中π是投影算子,σ是选择算子,ρ是重命名算子)
这会计算两个或更多人预订的所有船只的 ID。现在我要去取所有由两个或更少的人预订的船。为此,我将选择三个或更多人保留的所有船,并通过从原始表中选择该集合中不存在的所有行来获取集合的补充。它不会很漂亮,但它是这样的:
π(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) )
)
))
你看,我选择了所有具有属性的行,然后从原始表中选择了所有不具有这些属性的行,将所有不具有属性的行都排除在外,这意味着所有的船都没有三人及以上包船,两人以下包船。
要获得恰好有两个人预订的船,只需将其与多个人预订的船相交即可。
π( 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) )
)
)
)
呃。太丑了,让人心疼。我希望我知道一个更好的符号。
SQLishly,我认为它可能看起来像这样:
(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
)
请注意,这正是 onedaywhen 的解决方案,除了我将集差表示为取与补码的交集。