SQL选择仅包含子项的父项

时间:2012-12-19 21:24:20

标签: sql tags parent subset

如果你有父表

create table parent (
  pid int not null,
  name varchar(255)
)

和父子联接表

create table parent_child (
  pid int not null,
  cid int not null,
  foreign key (pid) references parent(pid),
  foreign key (cid) references child(cid)
)
create table child(
  cid int not null,
  name varchar(255)
)

如何在以下列表中找到所有孩子姓名的所有父母姓名('dave','henry','myriam','jill')。

我不希望看到父母是否有一个名字不同的孩子,但是如果他们有一个或多个孩子并且他们所有孩子的名字都在列表中我想看到父母的名字。

我确实找到了这个https://stackoverflow.com/a/304314/1916621,这将帮助我找到一个有这些名字的孩子的父母,但我无法弄清楚如何只有孩子在该列表的子集中有名字的孩子

如果有人知道不同方法的性能权衡,那么额外的分数。

2 个答案:

答案 0 :(得分:3)

SELECT 
    p.pid, 
    p.name
FROM 
    parent p
WHERE NOT EXISTS (
    SELECT *
    FROM 
        parent_child pc 
        JOIN child c 
            ON pc.cid = c.cid
            AND c.name NOT IN ('dave','henry','myriam','jill')
    WHERE 
        p.pid = pc.pid
) AND EXISTS (
    SELECT *
    FROM 
        parent_child pc 
        JOIN child c 
            ON pc.cid = c.cid
            AND c.name IN ('dave','henry','myriam','jill')
    WHERE 
        p.pid = pc.pid
)

另一种方法......没有子查询,但需要额外的DISTINCT来消除重复parent个记录加入parent_child表。

SELECT DISTINCT
    p.pid, 
    p.name
FROM 
    parent p 
    JOIN parent_child pc_exists ON pc_exists.pid = p.pid
    JOIN child c_exists 
        ON c_exists.cid = pc_exists.cid
        AND c_exists.name IN ('dave','henry','myriam','jill')
    LEFT JOIN parent_child pc_notExists ON pc_notExists.pid = p.pid
    LEFT JOIN child c_notExists 
        ON c_notExists.cid = pc_notExists.cid
        AND c_notExists.name NOT IN ('dave','henry','myriam','jill')
WHERE
    c_notExists.cid IS NULL

答案 1 :(得分:1)

这是我温和的赌注:

示例表:

<强>父

PID     NAME
1       dad john
2       mum sandy
3       dad frank
4       mum kate
5       mum jean

儿童

CID     NAME
11      dave
22      maryam
33      henry
44      maryam
16      jill
17      lina
23      jack
34      jill
55      dave

<强> Parent_Child

PID     CID
1       11
1       16
1       17
2       22
3       33
4       44
2       23
5       55
3       34

查询:

select p.pid, p.name, 
group_concat(c.name) as children
from parent as p
inner join parent_child as pc
on p.pid = pc.pid
join child as c
on pc.cid = c.cid
where c.name
in ('dave','henry','maryam','jill')
group by p.pid
;

结果:

PID     NAME        CHILDREN
1       dad john    dave,jill
2       mum sandy   maryam
3       dad frank   henry,jill
4       mum kate    maryam
5       mum jean    dave

使用REGEXP和GROUP_CONCAT

对于SQL来说,这比infind_in_set要好得多。我做的更改,我将列表用作comma delimitted string;)

*但问题在于:必须在comman delimitted字符串中找到group_concat字符串顺序。*除非我们使REGEXP更有效率:)

查询:

select x.pid, x.name,
x.children from(
select p.pid, p.name, 
group_concat(c.name) as children,
  count(c.name) as counts
from parent as p
inner join parent_child as pc
on p.pid = pc.pid
join child as c
on pc.cid = c.cid
group by p.pid) as x
where 'dave,maryam,henry,jill'
REGEXP x.children
;

结果:

PID     NAME        CHILDREN
3       dad frank   henry,jill
4       mum kate    maryam
5       mum jean    dave

*的 SQLFIDDLE