【问题标题】:Storing relationship in mysql database在mysql数据库中存储关系
【发布时间】:2011-02-06 01:53:55
【问题描述】:

我正在创建内容之间的多对多关系,但为了简化它,我现在将使用更简单的关系。一个例子是电影之间的关系。存储这些数据的正确方法是什么?

我最初是这样做的:

Movie | Related Movie | Relation (Relation of the related movie)
--------------------------------
Matrix   | Matrix 2 | Sequel
Matrix 2 | Matrix   | Prequel

所以 Matrix 2 是 Matrix 的续集,但后来我意识到存储相关电影的关系而不是实际电影的关系似乎没有意义。所以我尝试了这个:

Movie | Relation | Related Movie 
--------------------------------
Matrix   | Prequel | Matrix 2
Matrix 2 | Sequel  | Matrix

现在我存储的是电影的实际关系而不是相关的电影,因此该行更有意义。也更直白一点,《黑客帝国》是《黑客帝国2》的前传。

但是,然后我在前端使用第二种方式实现了 Matrix 页面看起来像这样: 前传 - 矩阵 2

对于 Matrix 2 页面: 续集 - 矩阵

所以第一种方式似乎更正确地将数据存储在后端,而不是前端。而第二种方式似乎在后端没有正确存储数据,但在前端更有意义。

那么在这种情况下,我是否应该以相反的方式存储数据(第二种方式)?我什至应该担心这一点吗?只要在前端有意义?

【问题讨论】:

    标签: mysql relationships storing-data


    【解决方案1】:

    您不需要同时存储向后和向前的关系。与链表不同的是,您不必存储prevnext 指针就可以前后遍历。

    例如,为什么不这样做:

    SELECT * FROM movies;
    +----+---------------+
    | id | title         |
    +----+---------------+
    |  1 | Matrix        |
    |  2 | Matrix 2      |
    |  3 | The Animatrix |
    +----+---------------+
    
    SELECT * FROM movie_relations;
    +----+----------+---------------+------------------+
    | id | movie_id | relation_type | related_movie_id |
    +----+----------+---------------+------------------+
    |  1 |        1 | sequel        |                2 |
    |  2 |        1 | offshoot      |                3 |
    |  3 |        2 | offshoot      |                3 |
    +----+----------+---------------+------------------+
    

    现在,如果你需要找到 Matrix 的所有续集:

    SELECT related_movie_id FROM movie_relations 
    WHERE movie_id = 1 AND relation_type = 'sequel'
    

    如果您需要查找矩阵 2 的所有前传,您知道这只是以related_movie_id 2 作为续集的电影列表:

    SELECT movie_id FROM movie_relations 
    WHERE related_movie_id = 2 AND relation_type = 'sequel'
    

    假设您需要所有与 Matrix 2 相关的电影(它有一个隐含的前传和一个直接指定的分支):

    SELECT DISTINCT(movies.id), title FROM movies 
        LEFT JOIN movie_relations mr_direct ON mr_direct.related_movie_id = movies.id 
        LEFT JOIN movie_relations mr_implicit ON mr_implicit.movie_id = movies.id 
    WHERE mr_direct.movie_id = 2 OR mr_implicit.related_movie_id = 2;
    
    +----+---------------+
    | id | title         |
    +----+---------------+
    |  1 | Matrix        |
    |  3 | The Animatrix |
    +----+---------------+
    

    查询比存储冗余数据稍微复杂一些。但是,我宁愿不要在不必要的地方重复信息。

    【讨论】:

    • 嗯,但是这样做更难获得实际相关电影的标题,而不是电影标题本身。 IE。如果我想知道 Matrix 相关电影的标题,我会使用:SELECT title FROM movies m INNER JOIN movies_relations mr ON m.id = mr.movie_id WHERE m.id = 1 但这会给我“Matrix”的标题,这是实际电影本身,而不是相关电影的标题。也许我的查询错了?这样做,您还必须来回翻转 select 和 where 字段。使用我使用的原始方式,我可以坚持一个查询。
    • 查询是向后的:SELECT movies.title FROM movies LEFT JOIN movie_relations ON movie_relations.related_movie_id = movies.id WHERE movie_relations.movie_id = 1; 将拉出正确的相关电影。我将更新我的答案以显示它如何处理多个关系,并在一个查询中完成。
    • 感谢您显示查询,这看起来很简单,但又有点复杂。现在的问题是如何显示相关电影的关系类型以及标题。例如,我想要 Matrix 2 相关电影的结果为:Matrix (Prequel)、The Animatrix (Offshoot)。如果我将relation_type 作为字段添加到选择中,我会得到Matrix (Sequel)、The Animatrix (Null)。既然续集没有办法知道对面是前传,你会怎么用你的方法做到这一点?
    • 您必须在 SELECT 中添加 IF 语句。但是,既然您提到需要这些字段,我认为您最初保留冗余数据的想法是可行的(相关电影的关系)。
    最近更新 更多