没有额外的桌子的多对多

时间:2015-02-25 12:18:19

标签: mysql sql

我在operation数据库中有两个表sourcemysql

operation我有10行(可能性),source只有3行(可能性),在它们之间存在many-to-many关系。
问题:是否需要添加此额外表格,或者只需在source中添加operation的外键。

operation可以是订阅请求,订阅启用,订阅禁用,订阅取消,付款确定,订阅交易确定,订阅开始。

source可以来自互联网,来自代理商

来源有共同的操作和独立的操作。

操作subscribe enabled可以通过互联网订阅或代理订阅和操作来完成:subscribe deal ok可以仅来自代理,subscribe request可以来自互联网。

6 个答案:

答案 0 :(得分:7)

在关系数据库中,您需要3个表来建立多对多的关系。两个包含主键和连接表。别无他法。

答案 1 :(得分:6)

对于简短而简短的回答,通常,对于像mysql这样的rdbms,只支持一对多关系,你需要第3个(交叉或交叉引用)表来实现多对多两个实体之间的关系。

<强>可是...

由于您没有太多记录,因此您可以将sourceoperation之间的多对多关系映射到仅一个附加列 source并且没有冗余数据存储。但是,你可能会失去一些性能(例如:不那么强大的索引),并且肯定会让你的生活更难以使用这些表......

诀窍是在operation表中使用特定的二进制值作为主键值,并在source表中添加一个整数列,在该表中使用其位来映射关系。因此,本专栏的一部分描述了实际源记录与相应操作记录之间的一种关系。

对于样本operation表,您可以创建一个表格,其中包含bit类型的pri键,其大小等于您估计的行数。你说你将有~10行,所以使用bit(10)作为数据类型。因为mysql会将int存储在4个字节上,所以你不必在这里放松存储大小(相反,与int相比,你实际上可能会赢得一些,但这实际上是dbe如何能够压缩实际上,如果你愿意的话,你也可以简单地使用int。)

create table operation (id bit(10) primary key, title varchar(50));

insert into operation values (b'0', 'none');
insert into operation values (b'1', 'subscribe request');
insert into operation values (b'10', 'subscribe enabled');
insert into operation values (b'100', 'subscribe disabled');
insert into operation values (b'1000', 'subscribe canceled');
insert into operation values (b'10000', 'payment ok');
insert into operation values (b'100000', 'subscribe deal ok');
insert into operation values (b'1000000', 'subscribe start');

现在,假设您的源表中包含以下内容:

create table source (id int primary key, value int, operations bit(10));

insert into source values (1, 1, b'0');
insert into source values (2, 2, b'1'); -- refers to subscribe request
insert into source values (3, 3, b'10'); -- refers to subscribe enabled
insert into source values (4, 4, b'10011'); -- refers to payment ok, subscribe request, subscribe enabled
insert into source values (5, 5, b'1110011'); -- refers to subscribe deal ok, subscribe start, payment ok, subscribe request, subscribe enabled

现在,如果您希望选择所有关系,请按以下方式连接这两个表:

select source.id, operation.title
from source
join operation
  on (source.operations & operation.id);

id  operation.title
2   subscribe request
4   subscribe request
5   subscribe request
3   subscribe enabled
4   subscribe enabled
5   subscribe enabled
4   payment ok
5   payment ok
5   subscribe deal ok
5   subscribe start

如果您希望添加新关系,您可以利用插入的on duplicate key update条款,因此您不必担心现有关系:

insert into source (id,value,operations)
   values (2,2,(select id from operation where title = 'subscribe start'))
on duplicate key update operations = operations
   | (select id from operation where title = 'subscribe start');

如果您希望删除关系

update source set operations = operations
   & ~(select id from operation where title = 'subscribe start') where source.id=2;

总而言之,这不是一个不错的选择,而是将多对多关系映射到两个表格的可能方式。

答案 2 :(得分:2)

根据您的实际需要,您的问题可以有很多答案。

实际上,在描述的情况下,您可以只使用一个表“操作”,并将source列定义为MySQL SET类型。然后,您将能够为每个操作选择0到多个来源。

然后,您可以更改表操作以设置源列

  ALTER TABLE operation ADD source SET('from internet', 'from agent');

如果你真的需要有两个表(假设你的“源”表包含其他字段),你应该有第三个表来建立它们之间的关系。

但是,从技术上讲,有些情况下,出于性能原因,您可能更喜欢将外键存储在其中一个表的varchar()字段中,并使用逗号分隔符,并使用PHP来检索数据。但这并不是做到这一点的好方法,尽管是可能的,只要你的数据检索只在一个方向完成,而你真的确定你在做什么。

例如,在这种“hacky-way”中,您可以想象一个类似ActiveRecord的PHP类,您可能希望使用这样的方法检索您的源

 public function getSources() {
    private $_sources;
    if (!isset($this->_sources)) {
        $this->_sources=DBSource::findByPks(explode(",", $this->sources));
    }
    return $this->_sources;
 }

答案 3 :(得分:1)

根据您描述的问题,您似乎不一定要有多对多的关系,因为 来源&#39;和&#39; 操作&#39;是枚举(一组常量值)。因此,&#39; 来源&#39;和&#39; 操作&#39;不要作为一个表,而是作为数据类型(即列类型)。

您可以查看Enums in mySQL并创建自己的&#39; 来源&#39;和&#39; 操作&#39;枚举并将它们放入一个表格中,以保持这种“多对多关系”#34;。

请记住,对于我提议的解决方案,我假设<#39; 来源&#39;和&#39; 操作&#39;拥有一组恒定且已知的值。如果不是这样,那么你会遇到麻烦,就像你有一个非规范化的数据库一样。

答案 4 :(得分:1)

我建议你采取最简单的方法解决问题,通常是最好的方法。只有在真正需要时才使用多对多关系。

您写道:

  

在源中只有3行(可能性)

     

来源可以来自互联网,来自代理商

这只是两个选择。

为什么没有source这样:

  1. 来自互联网
  2. 来自代理商
  3. 来自互联网&amp;剂
  4. 基本上,如果您非常确定source s的集合不会增长,您可以对所有变体进行硬编码。它以这种方式进行了优化,但是你失去了灵活类似于@lp_的答案。

答案 5 :(得分:1)

如果您知道在源表中最多有3行,您可以使用如下所示的操作表将关系映射到3(而不是多对多)

operation
---------
id_source_1
id_source_2
id_source_3

如果您不知道源中有多少行,则需要第三个表,因为只有第三个表才能映射多对多关系。