【问题标题】:SQL Select Many to ManySQL 多对多选择
【发布时间】:2014-09-25 23:32:48
【问题描述】:

我正在使用 MYSQL 5.X,但无法找出查询;

我有 2 个具有多对多关系的实体。

客户和服务,因此我有 3 个表:

客户端、clients_has_services 和服务。

我需要选择与特定客户无关的每个服务。

例如: 我有 ID 为 1 的客户端,总共有 4 个服务(Service1、Service2、Service3、Service4),客户端 1 与 Service1 有关系)所以我需要检索所有其他服务(Service2、Service3、Service4)

建议?

【问题讨论】:

    标签: mysql join many-to-many


    【解决方案1】:

    首先,获取一组services

    将它加入到来自clients 的行中,用于“特定客户”,这样您就拥有了该客户的一组所有服务。

    “诀窍”是使用反连接模式来排除 clients_have_services 表中存在“匹配”的行。

    如果您有客户端的唯一标识符(并且您只需要单个客户端的列表),则如下所示:

    SELECT s.*
      FROM services s
      LEFT
      JOIN clients_have_services h
        ON h.service_id = s.id
       AND h.client_id = 42
     WHERE h.service_id IS NULL
     ORDER BY s.id
    

    外连接返回来自services 的所有行,以及来自clients_have_services 表的任何“匹配”行。 “技巧”是 WHERE 子句中的谓词,它排除找到匹配项的任何行,只留下与特定客户端无关的 services

    如果您为多个客户端执行此操作...您还需要返回与服务交叉连接的客户端(作为客户端和服务的交叉产品),然后排除匹配项。

    例如:

    SELECT c.id AS client_id
         , s.*
      FROM clients c
     CROSS 
      JOIN services s
      LEFT
      JOIN clients_have_services h
        ON h.service_id = s.id
       AND h.client_id = c.id
     WHERE h.service_id IS NULL
     ORDER BY c.id, s.id
    

    还有一些其他查询模式会返回等效结果,例如NOT EXISTS

    SELECT s.*
      FROM services s
     WHERE NOT EXISTS 
           ( SELECT 1
               FROM clients_have_services h
              WHERE c.client_id = 42
                AND h.service_id = s.id
           )
     ORDER BY s.id
    

    【讨论】:

    • 你的回答有效,但是你在 AND 之后输入了一个“n”而不是“h”
    • 那是一个错字。 (在我看来,Ann 看起来很像 h。(至少查询会返回错误,而不是错误的结果。)
    • 是的,请解释一下:D 竖起大拇指!
    【解决方案2】:

    假设您的 client_has_services 纠正了多对多,因此您在双方都有一对多,所以您的 client_has_services 应该有: ID(密钥)、Client_ID、Service_ID

    SELECT * FROM services WHERE services.id != ANY (select client_has_services.services_id from client_has_services where client_has_services.client_id = ID_num_provided)

    【讨论】:

    • 子查询返回多行时,这个查询不会报错吗?也许如果 != 不等式比较被替换为 NOT IN 运算符,并且我们保证子查询不返回 NULL 值,这将起作用。
    • 如果返回多于一行,则不是问题。它将为返回的每一行重新运行“超级查询”。似乎违反直觉,但它确实有效。
    • 您是否有该行为的参考,或演示它的示例?我希望您回答中的查询会引发错误 1242“子查询返回超过 1 行”。 http://dev.mysql.com/doc/refman/5.5/en/subquery-errors.html
    • 更新为在比较器之后包含“ANY”。现在应该按照您的链接工作。我在 Oracle 中做了很多这样的事情,那里的语法不需要 ANY 运算符,并且可以很好地处理返回的多行。我一开始就错过了这个错误。
    猜你喜欢
    • 2011-03-30
    • 2023-04-10
    • 1970-01-01
    • 2012-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-31
    • 1970-01-01
    相关资源
    最近更新 更多