可以将按位数学用于SQL中的一对多关系吗?

RDBMS中的正确规范化意味着表的扩散。 整数字段可以将正交数据存储为位 – 这可以用作替代附加表,而不会牺牲关系完整性吗?

你的问题的答案是“不”。 位字段牺牲了关系完整性,原因很简单,因为数据库中的实体没有相应的表。

也就是说,许多数据库通常通过“位”数据类型提供支持。 Mysql具有更强大的支持,具有“set”数据类型。

主要问题是您对集合中的元素一无所知 – 全名是什么,何时添加到数据库中,等等。 (枚举可以解决部分命名问题。)此外,集合的大小也是有限的。 你可能有一个事物有限的例子。 然而,马特的例子在这里强调了这个问题。 您可以列出访问过的各大洲。 但是,当您切换到访问过的国家时,方法必然会有很大不同,因为国家/地区的数量不再适用于单个“单词”。 您是否希望您的系统在这方面与各国的处理方式截然不同? 您是否希望您的设计决策受到计算机字中32或64位的限制?

最后,您似乎将表的扩散视为一个问题。 表的扩散实际上是一种解决方案。 有关实体的所有数据都存储在表中,而不是通过系统传播。 您可以维护有关实体实例的信息,例如创建实例的时间,实例可能随时间的变化情况等等。 每当有人想要一个大陆时,很可能会使用“大陆”的实体。

考虑一下两个不同的开发人员决定为各大洲开发自己的位掩码的系统会发生什么 – 但他们把各大洲的顺序排在不同的位置。 使用设计良好的关系数据库(意味着在表定义中显式声明了外键关系),不会出现这种混淆。

对于一对多关系,其中“many”具有少量已知值,关系可以作为整数存储为父表中的位掩码,从而替代对另外的表的需要。

假设我们有一个表人员,我们想知道一个人访问了多少个大陆。 我们首先为每个大陆分配一个“正交”比特值。 在C#中,枚举是一个很好的选择:

[Flags] public enum JobAdvertisingRegion { NorthAmerica = 1, // or 1 << 0 SouthAmerica = 2, // 1 << 1 Europe = 4, // 1 << 2 Asia = 8, // 1 << 3 Africa = = 16, // 1 << 4 Australia = 32, // 1 << 5 Anarctica = 64 // 1 << 6 } 

然后,Persons表可以只有一个名为Contintents的int列。 表明某人已访问过欧洲和亚洲:

 UPDATE Persons SET Continents = (4 + 8) WHERE Id = whatever 

要搜索访问过南极洲的人,我们使用按位数学:

 SELECT * FROM Persons WHERE Continents & 64 = 64 

搜索访问过非洲和亚洲的人员:

 SELECT * FROM Persons WHERE Continents & (16 + 8) = (16 + 8) 

要搜索访问过澳大利亚或南美洲的人员:

 SELECT * FROM Persons WHERE Continents & (32 + 2) != 0 

一个缺点是,虽然整数列在SQL中是可索引的,但它们的位组件却不是。 对于上述查询,有些优化可以解决这个问题:

 SELECT * FROM Persons WHERE Continents & 64 = 64 AND Continents >= 64 SELECT * FROM Persons WHERE Continents & (16 + 8) = (16 + 8) AND Continents >= (16 + 8) SELECT * FROM Persons WHERE Continents & (32 + 2) != 0 AND Continents >= 2 

好吧,我会通过简单陈述一些事实来反对(目前)流行的观点

  • SQL和关系模型不是一回事。
  • 关系模型(理论)适用于关系变量,即所谓的relvars
  • SQL数据库使用表。
  • 表和relvars不一样,但可以 – 出于所有实际目的。
  • 要使用关系建模理论,表应代表relvars。
  • 对于表示关系变量的表,以下内容应为true:

    1. 行没有订单
    2. 列没有订单
    3. 没有重复的行
    4. 每个列 – 行交集只有一个列定义类型的值
    5. 没有特殊的隐藏列(row-id,object id ……)

因此,您可以使用超出关系设计理论范围的表和SQL做很多事情,但是您确实失去了“关系”的好处……

从技术上讲,你的post(问题)有两个答案。

  • 是的,到post的标题。
  • 不,到post的主体。