具有ManyToMany自引用关系的数据库模式

时间:2015-07-24 10:10:13

标签: mysql database-schema

我正在设计MySQL数据库架构,我不确定我的方法是否足够好。

想象一下这种情况:

  • 有一些人
  • 每个人都喜欢互联网上的一些文章(成千上万的文章)
  • 每篇文章都被翻译成另一种语言(数十种语言,可以在不同的网站上进行不同的翻译)

我希望能够指定文章名称,源语言,目标语言并查找本文的所有翻译。此外,我可以指定一个人,只查找他/她的“收藏夹”中的文章。

我的想法:

创建4个表:

CREATE TABLE Language (
    `id` INT NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(30) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB; 

CREATE TABLE Person (
    `id` INT NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(50) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB;

CREATE TABLE Article (
    `id` INT NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(100) NOT NULL,
    `language` INT NOT NULL,
    `person` INT NOT NULL,
    PRIMARY KEY (`id`),
    FOREIGN KEY (`language`) REFERENCES Language (`id`),
    FOREIGN KEY (`person`) REFERENCES Person (`id`)
) ENGINE=InnoDB;

CREATE TABLE Relation (
    `article_1` INT NOT NULL,
    `article_2` INT NOT NULL,
    PRIMARY KEY (`article_1`, `article_2`),
    FOREIGN KEY (`article_1`) REFERENCES Article (`id`) ON DELETE CASCADE,
    FOREIGN KEY (`article_2`) REFERENCES Article (`id`) ON DELETE CASCADE
) ENGINE=InnoDB;

将每篇文章存储为表格中的记录,并使用链接表Relation“连接”它们。

每个人都会创建一个文件,其中包含他/她最喜欢的文章的URL和翻译链接:

url1_en url1_es url1_de url1_ko
url2_en url2_es url2_de url2_ko
url3_en url3_es url3_de url3_ko
url4_en url4_es url4_de url4_ko

当然,另一个人可以为文章url1_en找到另一个德语翻译并上传它:

url1_en url1_es url1_de_2 url1_ko

如果我将使用德语作为目标语言搜索url1_en,我应该url1_deurl_1_de_2

这里的问题是如何处理这种自我引用的多对多文章关系。表关系也会快速增长。

也许有更好的方法来设计架构?

1 个答案:

答案 0 :(得分:3)

一般来说,你的方法还可以。但是我发现了一个错误。文章不应该与人有关 - 如果两个人喜欢同一篇文章会怎么样?

此外,由于某人可能喜欢一篇文章(而不是其翻译),因此您可以添加一个更高级别的复杂性。文章只是一个没有内容的容器,内容在ArticleTranslation表中

我提出的架构如下所示(我只关注表关系):

Article
  *..* Person [with join table PersonArticle]
  1..* ArticleContent

Person
   *..* Article [with join table PersonArticle]

然后,您的查询将如下(再次 - 伪代码):

  

查找翻译

SELECT ac2.* FROM Article a
    JOIN ArticleContent ac1
    JOIN ArticleContent ac2 (ac1.Article=ac2.Article)
WHERE ac1.name=<NAME>
   AND ac1.language=<SRC_LANG> 
   AND ac2.language=<TRG_LANG>
  

查找用户收藏的翻译

SELECT ac2.* 
FROM 
    Person p
    JOIN PersonArticle pa
    JOIN Article a
    JOIN ArticleContent ac1
    JOIN ArticleContent ac2 (ac1.Article=ac2.Article)
WHERE 
   p.id=<PERSON_ID>
   ac1.name=<NAME>
   AND ac1.language=<SRC_LANG> 
   AND ac2.language=<TRG_LANG>

UPDATE - 对于非常大量的数据,您可以考虑使用一些NoSQL方法。其中一些是专门为了映射这些数据图而创建的。然而,这是一个更复杂的解决方案,SQL对初学者有好处。