简体   繁体   English

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

[英]MySQL filter many elements from many-to-many relationship

I'm currently working on objects that are linked through a many-to-any relationship (it means that many objects can be linked to... not many objects of the same type, but many objects which type can vary). 我目前正在处理通过多对多关系链接的对象(这意味着可以将许多对象链接到...相同类型的对象不多,但类型可以变化的对象也很多)。

But, for this question, a many-to-many will be plenty enough. 但是,对于这个问题,多对多就足够了。

So, let's say I have a ObjectA table, with the following : 因此,假设我有一个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
);

Let's say I want to filter the ObjectA with 2 or three elements from ObjectB. 假设我要用ObjectB中的2个或3个元素过滤ObjectA。 You will think that I should use a IN : 您会认为我应该使用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);

But, the thing is, with this request, it gets all the objectAs that are linked with at least ONE of the ObjectBs searched (here, 1, 2, and 3). 但是,问题是,通过此请求,它获取与至少一个搜索到的ObjectB(此处为1、2和3)链接的所有objectAs。 But, what I want, are those that have all the ObjectB's 1, 2 and 3. 但是,我想要的是那些具有所有 ObjectB的1、2和3的对象。

I already tried some things (like the ALL possibility, or pondering to make a first filter outside of SQL), but it didn't give the expected results. 我已经尝试了一些方法(例如ALL可能性,或者正在考虑在SQL之外进行第一个过滤器),但是并没有得到预期的结果。

Any ideas ? 有任何想法吗 ?


To sum up, I'd like to be able to do a bit like the issues from GitHub and how they are filtering their label. 综上所述,我希望能够像GitHub上的问题以及它们如何过滤标签那样做。 If you pick up a bunch of labels, only the issues that have all the selected labels are returned, rather than all the issues that have at least one label. 如果拾取一堆标签,则仅返回具有所有选定标签的问题,而不是具有至少一个标签的所有问题。

Thanks ! 谢谢 !

From your comments it sounds like you don't want LEFT JOIN which will return ALL ObjectA s which match the WHERE clause. 从您的评论看来,您不希望LEFT JOIN将返回与WHERE子句匹配的所有ObjectA As for the relation condition you have to count the matching rows: 至于关系条件,您必须计算匹配的行:

  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;

If you don't actually need the ObjectB data in this query you can simplify this even further: 如果您实际上在此查询中不需要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;

This assumes that you can only have one of each ObjectB.id linked to an ObjectA through the pivot table. 这是假设你只能各有一个ObjectB.id链接到一个ObjectA通过透视表。

A solution is to count the matching conditions in an having clause. 一种解决方案是在Have子句中计算匹配条件。

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;

See sqlfidle example . 请参见sqlfidle示例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM