MySQL从多对多关系中过滤掉许多元素

时间:2014-07-29 12:48:19

标签: mysql sql many-to-many conditional-statements

我目前正在处理通过多对多关系链接的对象(这意味着许多对象可以链接到...不是很多相同类型的对象,但许多类型的对象可能会有所不同)

但是,对于这个问题,多对多就足够了。

所以,假设我有一个ObjectA表,其中包含以下内容:

CREATE TABLE (
    id INT(11) NOT NULL, 
    label VARCHAR(30) NOT NULL,
    -- primary keys and all the stuff
);

CREATE TABLE ObjectB (
    id INT(11) NOT NULL,
    label VARCHAR(30) NOT NULL,
    -- primary keys and all the stuff
);

CREATE TABLE ObjectA_ObjectB (
    objectA_id INT(11) NOT NULL,
    objectA_type VARCHAR(250) NOT NULL, -- for the many to any
    objectB_id INT(11) NOT NULL,
    -- primary keys and all the stuff
);

假设我想用ObjectB中的2或3个元素过滤ObjectA。您会认为我应该使用IN

SELECT *
    FROM ObjectA a
        LEFT JOIN ObjectA_ObjectB relation ON a.id = relation.objectA_id AND "ObjectA" = relation.objectA_class
        LEFT JOIN ObjectB b ON relation.objectB_id = b.id
    WHERE b.id IN (1, 2, 3);

但是,有了这个请求,它会获得与至少一个搜索到的ObjectB(此处为1,2和3)链接的所有objectAs。但是,我想要的是那些全部 ObjectB的1,2和3。

我已经尝试了一些东西(比如ALL的可能性,或者想在SQL之外做第一个过滤器),但它没有给出预期的结果。

有什么想法吗?


总而言之,我希望能够做一些像GitHub的问题以及他们如何过滤他们的标签。如果您选择了一堆标签,则只返回所有所选标签的问题,而不是所有至少一个的问题 label。

谢谢!

2 个答案:

答案 0 :(得分:1)

从您的评论中听起来您不希望LEFT JOIN返回与ObjectA子句匹配的所有WHERE。至于关系条件,你必须计算匹配的行:

  SELECT *
    FROM ObjectA a
    JOIN ObjectA_ObjectB relation 
      ON a.id = relation.objectA_id 
     AND "ObjectA" = relation.objectA_class
    JOIN ObjectB b 
      ON relation.objectB_id = b.id
GROUP BY a.id
  HAVING COUNT(CASE WHEN b.id IN (1,2,3) THEN 1 ELSE NULL END)=3;

OR:

  SELECT *
    FROM ObjectA a
    JOIN ObjectA_ObjectB relation 
      ON a.id = relation.objectA_id 
     AND "ObjectA" = relation.objectA_class
    JOIN ObjectB b 
      ON relation.objectB_id = b.id
     AND b.id IN (1,2,3)
GROUP BY a.id
  HAVING COUNT(*)=3;

如果您在此查询中实际上不需要ObjectB数据,则可以进一步简化此操作:

  SELECT a.*
    FROM ObjectA a
    JOIN ObjectA_ObjectB relation 
      ON a.id = relation.objectA_id 
     AND "ObjectA" = relation.objectA_class
     AND relation.objectB_id IN (1,2,3)
GROUP BY a.id
  HAVING COUNT(*)=3;

这假设您只能通过数据透视表将ObjectB.id中的一个链接到ObjectA

答案 1 :(得分:1)

解决方案是计算having子句中的匹配条件。

SELECT *
FROM ObjectA a
    JOIN ObjectA_ObjectB relation ON a.id = relation.objectA_id AND "ObjectA" = relation.objectA_class
    JOIN ObjectB b ON relation.objectB_id = b.id
WHERE b.id IN (1, 2, 3) GROUP BY a.id HAVING COUNT(b.id)=3;

请参阅sqlfidle example