知识卡片
UNIQUE量词及SQL近似实现
内容
除EXISTS/FORALL外,逻辑上还存在很多其他量词(”至少存在三个”“大多数”“奇数
个”等),实践中最重要的补充量词是UNIQUE(”仅存在一个x使得”):
UNIQUE x(p(x))表示恰好只有一个满足p的实参值。UNIQUE让一些约束的表述
变得远比用FORALL套嵌套IF更清晰——[[数据库约束的分类元组约束与AND聚集表述
法]]里CX3约束(供应商编号唯一)用FORALL嵌套写法笨拙冗长
(FORALL SX(FORALL SY(IF SX.SNO=SY.SNO THEN ...))),改用UNIQUE后变成
FORALL SX(UNIQUE SY(SX.SNO=SY.SNO))——”对每个供应商SX,恰好只有一个SY
和它SNO相同”,含义直接对应键约束的本质。同理,[[SQL不支持类型约束的后果与
弥补建议]]系约束里”SP中的SNO必须出现在S中”这条外键约束,如果用UNIQUE表述
成FORALL SPX(UNIQUE SX(SX.SNO=SPX.SNO))比原来的EXISTS写法更贴近真实
意图——原来的EXISTS写法之所以”碰巧可行”,只是因为额外依赖了”{SNO}是S的
键”这条约束在背后撑腰,UNIQUE版本才是对参照约束语义更精确的直接表达。
SQL间接支持UNIQUE:UNIQUE(SELECT k FROM T WHERE p(x))(k为任意常量)
近似表达”恰有一行满足p”,其定义是”当参数表不包含任何重复行时返回TRUE,
否则FALSE”——这意味着参数表只有一行或根本没有行时UNIQUE都返回TRUE(与
UNIQUE量词”区间为空则为FALSE”的严格定义并不完全一致),书中甚至评论
AT_MOST_ONE(或NO_DUPS)才是比UNIQUE更准确的SQL运算符命名。SQL的
UNIQUE(SNO)键约束声明本质上也是CHECK(UNIQUE(SELECT SNO FROM S))的
缩写,SELECT子句里绝不能加DISTINCT(这是[[避免重复的实践规则DISTINCT与
ALL的陷阱]]里”总是用DISTINCT”这条一般性建议的一次明确例外,因为这里恰恰
需要保留重复才能让UNIQUE判断出唯一性是否被违反)。