规范化现有多列多字符串表的最佳方法是什么?

时间:2014-08-05 01:49:29

标签: mysql

我是mysql的新手,所以非常感谢帮助: - )

让我们看电影db示例:

movie_td (mov_id auto_increment pk, title, year, duration)
actor_td (act_id auto_increment pk, name)
director_td (dir_id auto_increment pk, name)
movie_actor_td (movie_id fk, actor_id fk)
movie_director_td (movie_id fk, director_id fk)

我理解如何将.csv类型的文件插入到单个td中,其中所有名称都存储在一列中,但是以标准化格式执行此操作有点令人困惑。如果我已经将所有数据存储在一个表中,那么首先创建静态mov_id是否有意义,以便我可以引用其余的列?或者有更好的方法吗?

谢谢!

2 个答案:

答案 0 :(得分:0)

如果您将所有数据存储在一个表格中,如果您的任何电影中有多个演员或拥有多个导演,您将面临问题。

这种规范化的数据库方法最好避免在数据库表中插入,更新和删除冗余数据的异常。

此外,如果同一个演员与许多电影有关,你必须为电影的每一行写同一个名字(演员/导演)。因此,更新特定行而不是其他行中的actor / director名称将导致表中actor / director名称的不一致。

答案 1 :(得分:0)

如果按定义去,如果每个属性的域仅包含原子值,并且每个属性的值仅包含该域中的单个值,则关系处于第一范式。 (来源:wikipedia.org)。

因此,当您在行中插入由逗号分隔的多个值时,您违反了第一个NF本身!这是因为数据之间存在多对多关系,并且您没有正确映射它。

此外,您提出了一个非常基本的问题 - If I already have all the data stored in one table, does it make sense to create a static mov_id first so that I can reference the rest of columns to it? - 好吧,如果您只想将所有数据存储在一个表中,为什么不选择XML呢?您将拥有一个存储所有相关数据的文件。但事实是,您无法使用XML运行完整的应用程序。 XML有不同的用途,数据库表有不同的用途。您确实需要一个可以根据需要查询的数据结构,而不必担心存储的发生方式。我建议你阅读Korth关于数据库设计的书。

转而设计数据库和表结构,无论您是否知道如何将.csv文件存储到列中都无关紧要。重要的是开发复杂代码以从CSV列中获取值需要多长时间。编写一些简单的查询比使用复杂的搜索循环来获取值总是更好。

让我们看一下您发布的示例。我只拿了三张桌子。

考虑表movie_td(我不明白_td部分背后的原因,但我会坚持它,因为你发布了它。)这个表存储有关电影的信息。现在,在现实世界中,电影可能有多个属性(列),如标题,发布日期(现在,这也取决于它发布的区域,它可能有多个发布日期,因为每个区域,这是一个完全不同的故事),运行时间,导演的名字(到目前为止,我只看了一个导演或导演二人组的电影。我还没看过多导演的电影;)等等。

我们必须在此考虑两个事实:

  • 电影中有多个演员描绘多个角色。
  • 演员可能已经演过多部电影。

这为我们提供了演员和电影之间的多对多关系,这就是表格movie_actor_td出现的地方。此表存储哪个电影在哪个电影中投放,其中movie_idactor_id均为foreign key。电影可能在此表中有多个条目,针对那些演员。演员也可能在这张表中有多个条目来对付那些电影,因此这些电影之间保持着相互的多对多关系。

拥有这种结构的一个主要原因是查询表格。如果您存储在电影表中分隔的演员逗号的名称,则无法使用actor_id深入了解演员的数据 - 您无法获取演员的其他详细信息,例如他们的出生日期和其他生物数据。

如果有人问你演员foo完成了多少部电影怎么办?你会去每行的CSV列中寻找演员的名字吗?它会有多快?

但是现在您已经拥有了给定的表结构,您可以通过这样的简单查询找到它:

SELECT count(*)
  FROM movie_actor_td
 WHERE actor_id = (SELECT actor_id
                     FROM actor_td
                    WHERE name = 'foo');

让我们考虑一个更复杂的例子。为此,我可以自由地向表character_name添加列movie_actor_td,因为演员通常在电影中扮演单个角色。所以你的movie_actor_td表看起来像是:

movie_actor_td (movie_id, actor_id, character_name)

现在,有一位演员在1996年发行的电影James Bond中扮演Goldeneye。我不知道他的名字。我想知道他在2002年完成了多少部电影。我只想简单地提出一个问题:

SELECT COUNT(*)
  FROM movie_actor_td
 WHERE actor_id = (SELECT actor_id
                     FROM movie_actor_td
                    WHERE     movie_id = (SELECT movie_id
                                            FROM movie_td
                                           WHERE     name = 'Goldeneye'
                                                 AND release_year = 1996)
                          AND character_name = 'James Bond');

如果您将所有数据存储在一个CSV列中,是否可以轻松获取?我不信。 我建议您继续使用当前架构。

修改

您首先要求创建静态mov_id并将所有其他列引用到它。我认为您需要先阅读有关primary keysforeign keys和数据库约束的更多信息。然后阅读MySQL中自动增加的列值。