【问题标题】:Get rows with only one reference in many-to-many relationship在多对多关系中获取只有一个引用的行
【发布时间】:2014-04-17 14:19:44
【问题描述】:

我有三个具有多对多关系的 MySQL 表。

一张表用于任务,一张表用于用户,第三张用于分配任务给用户(每个任务可以分配给多个用户)。

users:           tasks:            assigned:
+----+------+    +----+-------+    +---------+---------+
| id | name |    | id | title |    | task_id | user_id |
+----+------+    +----+-------+    +---------+---------+
| 1  | John |    | 1  | One   |    |    1    |    1    |
+----+------+    +----+-------+    +---------+---------+
| 2  | Mike |    | 2  | Two   |    |    1    |    2    |
+----+------+    +----+-------+    +---------+---------+
                                   |    2    |    1    |
                                   +---------+---------+

如何将任务分配给一个用户?

如何将任务分配给仅一个特定用户?

【问题讨论】:

    标签: mysql many-to-many relationship


    【解决方案1】:

    您需要将所有表连接在一起。使用以下内容显示分配给 John 的所有任务:

    SELECT name,title
    FROM users
    JOIN assigned ON (user_id=users.id)
    JOIN tasks ON (tasks.id=task_id)
    WHERE name="John";
    

    使用GROUP BYHAVING 查看仅分配给一个用户的所有任务。

    SELECT title 
    FROM tasks
    JOIN assigned ON (task_id=id)
    GROUP BY id
    HAVING count(*) = 1;
    

    在后者中,您不一定需要知道任务分配给了谁,只需知道它们只分配给一个用户即可。因此您不需要加入users 表。

    更新:

    您可以使用以下方法查找单独分配给 John 的任务:

    SELECT name,title 
     FROM tasks
      JOIN assigned ON (task_id=tasks.id)
      JOIN users ON (user_id=users.id)
     GROUP BY tasks.id
     HAVING COUNT(*) = 1 and name="John";
    

    这可能有两个原因:

    1. MySQL 允许在HAVING 子句中使用非聚合引用。
    2. COUNT(*)=1 强制 name 为单一值 - 即您不会处于 name 将同时包含“John”和“Mike”的情况。

    【讨论】:

    • 如果将连接另一个表(例如,包含每个任务的 cmets 的表),查询将无法按预期工作。为了使其始终按预期工作,HAVING 条件应从确切的列中评估 COUNT,例如:HAVING COUNT(DISTINCT user_id) = 1 and name="John"
    • 没错,它会失败同一个用户被多次分配给同一个任务。从语义上讲,它没有多大意义,通过将 (task_id, user_id) 声明为“已分配”表中的唯一性来避免它是值得的。当然,如果 id 在“users”或“tasks”表中不是唯一的,也会发生同样的情况。
    • 正如我之前提到的,如果加入另一个表并选择了它的列,它就会失败,因为它们会干扰COUNT(*)。它与assigned 中的非唯一用户ID 无关。当然,可以并且将会有非唯一的用户 ID,例如在带有用户 cmets 的表中。
    猜你喜欢
    • 2013-02-10
    • 1970-01-01
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 2019-07-17
    • 1970-01-01
    • 1970-01-01
    • 2016-07-20
    相关资源
    最近更新 更多