MySQL如何找到具有精确子集的父级?

时间:2013-05-19 06:55:30

标签: mysql sql

MySQL 5.5

parent table:
id | facts
child table:
parent_id | foreign_key | facts

现在,我想找到父母,他们拥有一定数量的孩子,不多也不少。类似的东西:

SELECT t1.`id` 
from `parent_table` t1 
  LEFT JOIN `child_table` t2 ON t1.id=t2.parent_id
WHERE t2.`fk` = 1 
  AND t2.`fk` = 3  
  AND t2.`fk` = 5 
  AND t2.`fk` = 7 
  AND t2.`fk` = 9

但是这也将获得这组孩子的父记录:1,2,3,5,7,9。我只想要那些确切的孩子的父母:1,3,5,7,9。

有办法吗?

编辑: child.parent_id和child.fk 都不是唯一的。 child.fk是链接到另一个表的外键。 (“多对多关系”)所以父母很可能有孩子1,2,3,5,7,9。我完成此查询的全部理由是尽量避免为1,3,5,7,9创建新​​的父级,如果这样的父级已存在。

4 个答案:

答案 0 :(得分:3)

假设child.id对于每个child.parent_id都是唯一的。

SELECT  a.id, a.facts
FROM    parent a
        INNER JOIN child b
            ON a.id = b.parent_ID
WHERE   b.id IN (1,3,5,7,9) AND        -- <<== list all ChildID here
        EXISTS                         -- <<== this part checks if the parent_ID
        (                              --           present on the EXISTS clause
            SELECT  parent_ID          --           which only filters parents
            FROM    child c            --           with 5 children
            WHERE   b.parent_ID = c.parent_ID
            GROUP   BY parent_ID
            HAVING  COUNT(*) = 5       -- <<== total number of children
        )
GROUP   BY a.id, a.facts
HAVING  COUNT(*) = 5                   -- <<== total number of children

答案 1 :(得分:1)

SELECT   parent_id
FROM     child_table
GROUP BY parent_id
HAVING   SUM(id IN (1,3,5,7,9)) = COUNT(*)
     AND COUNT(DISTINCT id) = 5

答案 2 :(得分:1)

这个问题被称为(确切的)关系划分。本文中有许多有用的代码和解释: Divided We Stand: The SQL of Relational Division

解决问题的一种方法:

SELECT p.id AS parent_id
FROM parent AS p
WHERE EXISTS
      ( SELECT * FROM child AS c
        WHERE c.fk = 1 AND c.parent_id = p.id)
  AND EXISTS
      ( SELECT * FROM child AS c
        WHERE c.fk = 3 AND c.parent_id = p.id)
  AND EXISTS
      ( SELECT * FROM child AS c
        WHERE c.fk = 5 AND c.parent_id = p.id)
  AND EXISTS
      ( SELECT * FROM child AS c
        WHERE c.fk = 7 AND c.parent_id = p.id)
  AND EXISTS
      ( SELECT * FROM child AS c
        WHERE c.fk = 9 AND c.parent_id = p.id)
  AND NOT EXISTS
      ( SELECT * FROM child AS c
        WHERE c.fk NOT IN (1,3,5,7,9) AND c.parent_id = p.id) ;

另一个类似问题的链接,在StackOverflow,你可以找到10多个不同的解决方案(注意:它不是用于精确的除法,而是用于余数的划分)和性能测试(对于Postgres):<强> How to filter SQL results in a has-many-through relation

答案 3 :(得分:1)

与eggyal的解决方案类似,但我只是想把它作为一种替代方案,因为它应该在RDBMS之间更加便携;

SELECT c.parent_id
FROM child_table c
GROUP BY c.parent_id
HAVING SUM(CASE WHEN c.id IN (1,3,5,7,9) THEN 1 ELSE -1 END) = 5

5是您想要匹配的IN子句中的子项的确切数量(在本例中为全部)

这将仅适用于不同的孩子,如果有重复,则会中断。

An SQLfiddle to test with